diff options
Diffstat (limited to 'Recon')
-rw-r--r-- | Recon/PowerView.ps1 | 608 |
1 files changed, 496 insertions, 112 deletions
diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1 index d95443f..c6ce1d2 100644 --- a/Recon/PowerView.ps1 +++ b/Recon/PowerView.ps1 @@ -749,7 +749,7 @@ filter Export-PowerViewCSV { if (Test-Path -Path $OutFile) { # hack to skip the first line of output if the file already exists - $ObjectCSV | Foreach-Object { $Start=$True }{ if ($Start) {$Start=$False} else {$_} } | Out-File -Encoding 'ASCII' -Append -FilePath $OutFile + $ObjectCSV | ForEach-Object { $Start=$True }{ if ($Start) {$Start=$False} else {$_} } | Out-File -Encoding 'ASCII' -Append -FilePath $OutFile } else { $ObjectCSV | Out-File -Encoding 'ASCII' -Append -FilePath $OutFile @@ -2857,7 +2857,7 @@ function Get-ObjectAcl { } try { - $Searcher.FindAll() | Where-Object {$_} | Foreach-Object { + $Searcher.FindAll() | Where-Object {$_} | ForEach-Object { $Object = [adsi]($_.path) if($Object.distinguishedname) { @@ -2888,7 +2888,7 @@ function Get-ObjectAcl { else { $_ } - } | Foreach-Object { + } | ForEach-Object { if($GUIDs) { # if we're resolving GUIDs, map them them to the resolved hash table $AclProperties = @{} @@ -3080,7 +3080,7 @@ function Add-ObjectAcl { } try { - $Searcher.FindAll() | Where-Object {$_} | Foreach-Object { + $Searcher.FindAll() | Where-Object {$_} | ForEach-Object { # adapted from https://social.technet.microsoft.com/Forums/windowsserver/en-US/df3bfd33-c070-4a9c-be98-c4da6e591a0a/forum-faq-using-powershell-to-assign-permissions-on-active-directory-objects $TargetDN = $_.Properties.distinguishedname @@ -4659,7 +4659,7 @@ function Get-NetGroup { # cause the cache to calculate the token groups for the user $UserDirectoryEntry.RefreshCache("tokenGroups") - $UserDirectoryEntry.TokenGroups | Foreach-Object { + $UserDirectoryEntry.TokenGroups | ForEach-Object { # convert the token group sid $GroupSid = (New-Object System.Security.Principal.SecurityIdentifier($_,0)).Value @@ -5085,7 +5085,7 @@ function Get-NetFileServer { $TargetUsers -Match $_.samAccountName } else { $True } - } | Foreach-Object { + } | ForEach-Object { # split out every potential file server path if($_.homedirectory) { SplitPath($_.homedirectory) @@ -5138,13 +5138,13 @@ function Get-DFSshare { .EXAMPLE PS C:\> Get-DFSshare - + Returns all distributed file system shares for the current domain. .EXAMPLE PS C:\> Get-DFSshare -Domain test - + Returns all distributed file system shares for the 'test' domain. #> @@ -5171,6 +5171,185 @@ function Get-DFSshare { $Credential ) + function Parse-Pkt { + [CmdletBinding()] + param( + [byte[]] + $Pkt + ) + + $bin = $Pkt + $blob_version = [bitconverter]::ToUInt32($bin[0..3],0) + $blob_element_count = [bitconverter]::ToUInt32($bin[4..7],0) + #Write-Host "Element Count: " $blob_element_count + $offset = 8 + #https://msdn.microsoft.com/en-us/library/cc227147.aspx + $object_list = @() + for($i=1; $i -le $blob_element_count; $i++){ + $blob_name_size_start = $offset + $blob_name_size_end = $offset + 1 + $blob_name_size = [bitconverter]::ToUInt16($bin[$blob_name_size_start..$blob_name_size_end],0) + #Write-Host "Blob name size: " $blob_name_size + $blob_name_start = $blob_name_size_end + 1 + $blob_name_end = $blob_name_start + $blob_name_size - 1 + $blob_name = [System.Text.Encoding]::Unicode.GetString($bin[$blob_name_start..$blob_name_end]) + #Write-Host "Blob Name: " $blob_name + $blob_data_size_start = $blob_name_end + 1 + $blob_data_size_end = $blob_data_size_start + 3 + $blob_data_size = [bitconverter]::ToUInt32($bin[$blob_data_size_start..$blob_data_size_end],0) + #Write-Host "blob data size: " $blob_data_size + $blob_data_start = $blob_data_size_end + 1 + $blob_data_end = $blob_data_start + $blob_data_size - 1 + $blob_data = $bin[$blob_data_start..$blob_data_end] + switch -wildcard ($blob_name) { + "\siteroot" { } + "\domainroot*" { + # Parse DFSNamespaceRootOrLinkBlob object. Starts with variable length DFSRootOrLinkIDBlob which we parse first... + # DFSRootOrLinkIDBlob + $root_or_link_guid_start = 0 + $root_or_link_guid_end = 15 + $root_or_link_guid = [byte[]]$blob_data[$root_or_link_guid_start..$root_or_link_guid_end] + $guid = New-Object Guid(,$root_or_link_guid) # should match $guid_str + $prefix_size_start = $root_or_link_guid_end + 1 + $prefix_size_end = $prefix_size_start + 1 + $prefix_size = [bitconverter]::ToUInt16($blob_data[$prefix_size_start..$prefix_size_end],0) + $prefix_start = $prefix_size_end + 1 + $prefix_end = $prefix_start + $prefix_size - 1 + $prefix = [System.Text.Encoding]::Unicode.GetString($blob_data[$prefix_start..$prefix_end]) + #write-host "Prefix: " $prefix + $short_prefix_size_start = $prefix_end + 1 + $short_prefix_size_end = $short_prefix_size_start + 1 + $short_prefix_size = [bitconverter]::ToUInt16($blob_data[$short_prefix_size_start..$short_prefix_size_end],0) + $short_prefix_start = $short_prefix_size_end + 1 + $short_prefix_end = $short_prefix_start + $short_prefix_size - 1 + $short_prefix = [System.Text.Encoding]::Unicode.GetString($blob_data[$short_prefix_start..$short_prefix_end]) + #write-host "Short Prefix: " $short_prefix + $type_start = $short_prefix_end + 1 + $type_end = $type_start + 3 + $type = [bitconverter]::ToUInt32($blob_data[$type_start..$type_end],0) + #write-host $type + $state_start = $type_end + 1 + $state_end = $state_start + 3 + $state = [bitconverter]::ToUInt32($blob_data[$state_start..$state_end],0) + #write-host $state + $comment_size_start = $state_end + 1 + $comment_size_end = $comment_size_start + 1 + $comment_size = [bitconverter]::ToUInt16($blob_data[$comment_size_start..$comment_size_end],0) + $comment_start = $comment_size_end + 1 + $comment_end = $comment_start + $comment_size - 1 + if ($comment_size -gt 0) { + $comment = [System.Text.Encoding]::Unicode.GetString($blob_data[$comment_start..$comment_end]) + #Write-Host $comment + } + $prefix_timestamp_start = $comment_end + 1 + $prefix_timestamp_end = $prefix_timestamp_start + 7 + # https://msdn.microsoft.com/en-us/library/cc230324.aspx FILETIME + $prefix_timestamp = $blob_data[$prefix_timestamp_start..$prefix_timestamp_end] #dword lowDateTime #dword highdatetime + $state_timestamp_start = $prefix_timestamp_end + 1 + $state_timestamp_end = $state_timestamp_start + 7 + $state_timestamp = $blob_data[$state_timestamp_start..$state_timestamp_end] + $comment_timestamp_start = $state_timestamp_end + 1 + $comment_timestamp_end = $comment_timestamp_start + 7 + $comment_timestamp = $blob_data[$comment_timestamp_start..$comment_timestamp_end] + $version_start = $comment_timestamp_end + 1 + $version_end = $version_start + 3 + $version = [bitconverter]::ToUInt32($blob_data[$version_start..$version_end],0) + + #write-host $version + if ($version -ne 3) + { + #write-host "error" + } + + # Parse rest of DFSNamespaceRootOrLinkBlob here + $dfs_targetlist_blob_size_start = $version_end + 1 + $dfs_targetlist_blob_size_end = $dfs_targetlist_blob_size_start + 3 + $dfs_targetlist_blob_size = [bitconverter]::ToUInt32($blob_data[$dfs_targetlist_blob_size_start..$dfs_targetlist_blob_size_end],0) + #write-host $dfs_targetlist_blob_size + $dfs_targetlist_blob_start = $dfs_targetlist_blob_size_end + 1 + $dfs_targetlist_blob_end = $dfs_targetlist_blob_start + $dfs_targetlist_blob_size - 1 + $dfs_targetlist_blob = $blob_data[$dfs_targetlist_blob_start..$dfs_targetlist_blob_end] + $reserved_blob_size_start = $dfs_targetlist_blob_end + 1 + $reserved_blob_size_end = $reserved_blob_size_start + 3 + $reserved_blob_size = [bitconverter]::ToUInt32($blob_data[$reserved_blob_size_start..$reserved_blob_size_end],0) + #write-host $reserved_blob_size + $reserved_blob_start = $reserved_blob_size_end + 1 + $reserved_blob_end = $reserved_blob_start + $reserved_blob_size - 1 + $reserved_blob = $blob_data[$reserved_blob_start..$reserved_blob_end] + $referral_ttl_start = $reserved_blob_end + 1 + $referral_ttl_end = $referral_ttl_start + 3 + $referral_ttl = [bitconverter]::ToUInt32($blob_data[$referral_ttl_start..$referral_ttl_end],0) + + #Parse DFSTargetListBlob + $target_count_start = 0 + $target_count_end = $target_count_start + 3 + $target_count = [bitconverter]::ToUInt32($dfs_targetlist_blob[$target_count_start..$target_count_end],0) + $t_offset = $target_count_end + 1 + #write-host $target_count + + for($j=1; $j -le $target_count; $j++){ + $target_entry_size_start = $t_offset + $target_entry_size_end = $target_entry_size_start + 3 + $target_entry_size = [bitconverter]::ToUInt32($dfs_targetlist_blob[$target_entry_size_start..$target_entry_size_end],0) + #write-host $target_entry_size + $target_time_stamp_start = $target_entry_size_end + 1 + $target_time_stamp_end = $target_time_stamp_start + 7 + # FILETIME again or special if priority rank and priority class 0 + $target_time_stamp = $dfs_targetlist_blob[$target_time_stamp_start..$target_time_stamp_end] + $target_state_start = $target_time_stamp_end + 1 + $target_state_end = $target_state_start + 3 + $target_state = [bitconverter]::ToUInt32($dfs_targetlist_blob[$target_state_start..$target_state_end],0) + #write-host $target_state + $target_type_start = $target_state_end + 1 + $target_type_end = $target_type_start + 3 + $target_type = [bitconverter]::ToUInt32($dfs_targetlist_blob[$target_type_start..$target_type_end],0) + #write-host $target_type + $server_name_size_start = $target_type_end + 1 + $server_name_size_end = $server_name_size_start + 1 + $server_name_size = [bitconverter]::ToUInt16($dfs_targetlist_blob[$server_name_size_start..$server_name_size_end],0) + #write-host $server_name_size + $server_name_start = $server_name_size_end + 1 + $server_name_end = $server_name_start + $server_name_size - 1 + $server_name = [System.Text.Encoding]::Unicode.GetString($dfs_targetlist_blob[$server_name_start..$server_name_end]) + #write-host $server_name + $share_name_size_start = $server_name_end + 1 + $share_name_size_end = $share_name_size_start + 1 + $share_name_size = [bitconverter]::ToUInt16($dfs_targetlist_blob[$share_name_size_start..$share_name_size_end],0) + $share_name_start = $share_name_size_end + 1 + $share_name_end = $share_name_start + $share_name_size - 1 + $share_name = [System.Text.Encoding]::Unicode.GetString($dfs_targetlist_blob[$share_name_start..$share_name_end]) + #write-host $share_name + $target_list += "\\$server_name\$share_name" + $t_offset = $share_name_end + 1 + } + } + } + $offset = $blob_data_end + 1 + $dfs_pkt_properties = @{ + 'Name' = $blob_name + 'Prefix' = $prefix + 'TargetList' = $target_list + } + $object_list += New-Object -TypeName PSObject -Property $dfs_pkt_properties + $prefix = $null + $blob_name = $null + $target_list = $null + } + + $servers = @() + $object_list | ForEach-Object { + #write-host $_.Name; + #write-host $_.TargetList + if ($_.TargetList) { + $_.TargetList | ForEach-Object { + $servers += $_.split("\")[2] + } + } + } + + $servers + } + function Get-DFSshareV1 { [CmdletBinding()] param( @@ -5183,7 +5362,7 @@ function Get-DFSshare { [String] $ADSpath, - [ValidateRange(1,10000)] + [ValidateRange(1,10000)] [Int] $PageSize = 200, @@ -5201,6 +5380,7 @@ function Get-DFSshare { $DFSSearcher.FindAll() | Where-Object {$_} | ForEach-Object { $Properties = $_.Properties $RemoteNames = $Properties.remoteservername + $Pkt = $Properties.pkt $DFSshares += $RemoteNames | ForEach-Object { try { @@ -5213,9 +5393,22 @@ function Get-DFSshare { } } } + + if($pkt -and $pkt[0]) { + Parse-Pkt $pkt[0] | ForEach-Object { + # If a folder doesn't have a redirection it will + # have a target like + # \\null\TestNameSpace\folder\.DFSFolderLink so we + # do actually want to match on "null" rather than + # $null + if ($_ -ne "null") { + New-Object -TypeName PSObject -Property @{'Name'=$Properties.name[0];'RemoteServerName'=$_} + } + } + } } catch { - Write-Warning "Get-DFSshareV2 error : $_" + Write-Warning "Get-DFSshareV1 error : $_" } $DFSshares | Sort-Object -Property "RemoteServerName" } @@ -5276,7 +5469,7 @@ function Get-DFSshare { } $DFSshares = @() - + if ( ($Version -eq "all") -or ($Version.endsWith("1")) ) { $DFSshares += Get-DFSshareV1 -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $ADSpath -PageSize $PageSize } @@ -5284,7 +5477,7 @@ function Get-DFSshare { $DFSshares += Get-DFSshareV2 -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $ADSpath -PageSize $PageSize } - $DFSshares | Sort-Object -Property "RemoteServerName" + $DFSshares | Sort-Object -Property ("RemoteServerName","Name") -Unique } @@ -5356,7 +5549,7 @@ function Get-GptTmpl { try { Write-Verbose "Parsing $GptTmplPath" - Get-Content $GptTmplPath -ErrorAction Stop | Foreach-Object { + Get-Content $GptTmplPath -ErrorAction Stop | ForEach-Object { if ($_ -match '\[') { # this signifies that we're starting a new section $SectionName = $_.trim('[]') -replace ' ','' @@ -5553,6 +5746,10 @@ function Get-NetGPO { The GPO display name to query for, wildcards accepted. + .PARAMETER ComputerName + + Return all GPO objects applied to a given computer (FQDN). + .PARAMETER Domain The domain to query for GPOs, defaults to the current domain. @@ -5591,6 +5788,9 @@ function Get-NetGPO { $DisplayName, [String] + $ComputerName, + + [String] $Domain, [String] @@ -5613,21 +5813,95 @@ function Get-NetGPO { process { if ($GPOSearcher) { - if($DisplayName) { - $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(displayname=$DisplayName))" + + if($ComputerName) { + $GPONames = @() + $Computers = Get-NetComputer -ComputerName $ComputerName -Domain $Domain -DomainController $DomainController -FullData -PageSize $PageSize + + if(!$Computers) { + throw "Computer $ComputerName in domain '$Domain' not found! Try a fully qualified host name" + } + + # get the given computer's OU + $ComputerOUs = @() + ForEach($Computer in $Computers) { + # extract all OUs a computer is a part of + $DN = $Computer.distinguishedname + + $ComputerOUs += $DN.split(",") | ForEach-Object { + if($_.startswith("OU=")) { + $DN.substring($DN.indexof($_)) + } + } + } + + Write-Verbose "ComputerOUs: $ComputerOUs" + + # find all the GPOs linked to the computer's OU + ForEach($ComputerOU in $ComputerOUs) { + $GPONames += Get-NetOU -Domain $Domain -DomainController $DomainController -ADSpath $ComputerOU -FullData -PageSize $PageSize | ForEach-Object { + # get any GPO links + write-verbose "blah: $($_.name)" + $_.gplink.split("][") | ForEach-Object { + if ($_.startswith("LDAP")) { + $_.split(";")[0] + } + } + } + } + + Write-Verbose "GPONames: $GPONames" + + # find any GPOs linked to the site for the given computer + $ComputerSite = (Get-SiteName -ComputerName $ComputerName).SiteName + if($ComputerSite -and ($ComputerSite -ne 'ERROR')) { + $GPONames += Get-NetSite -SiteName $ComputerSite -FullData | ForEach-Object { + if($_.gplink) { + $_.gplink.split("][") | ForEach-Object { + if ($_.startswith("LDAP")) { + $_.split(";")[0] + } + } + } + } + } + + $GPONames | Where-Object{$_ -and ($_ -ne '')} | ForEach-Object { + + # use the gplink as an ADS path to enumerate all GPOs for the computer + $GPOSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $_ -PageSize $PageSize + $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))" + + try { + $GPOSearcher.FindAll() | Where-Object {$_} | ForEach-Object { + $Out = Convert-LDAPProperty -Properties $_.Properties + $Out | Add-Member Noteproperty 'ComputerName' $ComputerName + $Out + } + } + catch { + Write-Warning $_ + } + } } + else { - $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))" - } + if($DisplayName) { + $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(displayname=$DisplayName))" + } + else { + $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))" + } - try { - $GPOSearcher.FindAll() | Where-Object {$_} | ForEach-Object { - # convert/process the LDAP fields for each result - Convert-LDAPProperty -Properties $_.Properties + try { + $GPOSearcher.FindAll() | Where-Object {$_} | ForEach-Object { + # convert/process the LDAP fields for each result + Convert-LDAPProperty -Properties $_.Properties + } + } + catch { + Write-Warning $_ } - } - catch { - Write-Warning $_ } } } @@ -5670,7 +5944,7 @@ function New-GPOImmediateTask { .PARAMETER GPODisplayName - The GPO display name to to build the task for. + The GPO display name to build the task for. .PARAMETER Domain @@ -5928,7 +6202,7 @@ function Get-NetGPOGroup { ) # get every GPO from the specified domain with restricted groups set - Get-NetGPO -GPOName $GPOname -DisplayName $GPOname -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize | Foreach-Object { + Get-NetGPO -GPOName $GPOname -DisplayName $GPOname -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize | ForEach-Object { $Memberof = $Null $Members = $Null @@ -6199,6 +6473,11 @@ function Find-GPOLocation { $GPOguid = $_.GPOName $GPOMembers = $_.Members + if(!$TargetObjects) { + # if the * wildcard was used, set the ObjectDistName as the GPO member sid set + $TargetObjects = $GPOMembers + } + if( -not $ProcessedGUIDs[$GPOguid] ) { $GPOname = $_.GPODisplayName $Filters = $_.Filters @@ -6217,12 +6496,8 @@ function Find-GPOLocation { $OUComputers = Get-NetComputer -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $_.ADSpath -PageSize $PageSize } - if(!$TargetObjects) { - # if the * wildcard was used, set the ObjectDistName as the GPO member sid set - $TargetObjects = $GPOMembers - } + ForEach ($TargetSid in $TargetObjects) { - ForEach ($TargetSid in $TargetObjects) { $Object = Get-ADObject -SID $TargetSid -Domain $Domain -DomainController $DomainController $_ -PageSize $PageSize $IsGroup = @('268435456','268435457','536870912','536870913') -contains $Object.samaccounttype @@ -6241,7 +6516,7 @@ function Find-GPOLocation { } # find any sites that have this GUID applied - Get-NetSite -Domain $Domain -DomainController $DomainController -GUID $GPOguid -PageSize $PageSize -FullData | Foreach-Object { + Get-NetSite -Domain $Domain -DomainController $DomainController -GUID $GPOguid -PageSize $PageSize -FullData | ForEach-Object { ForEach ($TargetSid in $TargetObjects) { $Object = Get-ADObject -SID $TargetSid -Domain $Domain -DomainController $DomainController $_ -PageSize $PageSize @@ -6361,6 +6636,8 @@ function Find-GPOComputerAdmin { Throw "-ComputerName or -OUName must be provided" } + $GPOGroups = @() + if($ComputerName) { $Computers = Get-NetComputer -ComputerName $ComputerName -Domain $Domain -DomainController $DomainController -FullData -PageSize $PageSize @@ -6368,16 +6645,42 @@ function Find-GPOComputerAdmin { throw "Computer $ComputerName in domain '$Domain' not found! Try a fully qualified host name" } + $TargetOUs = @() ForEach($Computer in $Computers) { # extract all OUs a computer is a part of $DN = $Computer.distinguishedname - $TargetOUs = $DN.split(",") | Foreach-Object { + $TargetOUs += $DN.split(",") | ForEach-Object { if($_.startswith("OU=")) { $DN.substring($DN.indexof($_)) } } } + + # enumerate any linked GPOs for the computer's site + $ComputerSite = (Get-SiteName -ComputerName $ComputerName).SiteName + if($ComputerSite -and ($ComputerSite -ne 'ERROR')) { + $GPOGroups += Get-NetSite -SiteName $ComputerSite -FullData | ForEach-Object { + if($_.gplink) { + $_.gplink.split("][") | ForEach-Object { + if ($_.startswith("LDAP")) { + $_.split(";")[0] + } + } + } + } | ForEach-Object { + $GPOGroupArgs = @{ + 'Domain' = $Domain + 'DomainController' = $DomainController + 'ADSpath' = $_ + 'UsePSDrive' = $UsePSDrive + 'PageSize' = $PageSize + } + + # for each GPO link, get any locally set user/group SIDs + Get-NetGPOGroup @GPOGroupArgs + } + } } else { $TargetOUs = @($OUName) @@ -6385,19 +6688,19 @@ function Find-GPOComputerAdmin { Write-Verbose "Target OUs: $TargetOUs" - $TargetOUs | Where-Object {$_} | Foreach-Object { - - $OU = $_ + $TargetOUs | Where-Object {$_} | ForEach-Object { # for each OU the computer is a part of, get the full OU object - $GPOgroups = Get-NetOU -Domain $Domain -DomainController $DomainController -ADSpath $_ -FullData -PageSize $PageSize | Foreach-Object { + $GPOgroups += Get-NetOU -Domain $Domain -DomainController $DomainController -ADSpath $_ -FullData -PageSize $PageSize | ForEach-Object { # and then get any GPO links - $_.gplink.split("][") | Foreach-Object { - if ($_.startswith("LDAP")) { - $_.split(";")[0] + if($_.gplink) { + $_.gplink.split("][") | ForEach-Object { + if ($_.startswith("LDAP")) { + $_.split(";")[0] + } } } - } | Foreach-Object { + } | ForEach-Object { $GPOGroupArgs = @{ 'Domain' = $Domain 'DomainController' = $DomainController @@ -6409,79 +6712,77 @@ function Find-GPOComputerAdmin { # for each GPO link, get any locally set user/group SIDs Get-NetGPOGroup @GPOGroupArgs } + } - # for each found GPO group, resolve the SIDs of the members - $GPOgroups | Where-Object {$_} | Foreach-Object { - $GPO = $_ + # for each found GPO group, resolve the SIDs of the members + $GPOgroups | Where-Object {$_} | ForEach-Object { + $GPO = $_ - if ($GPO.members) { - $GPO.members = $GPO.members | Where-Object {$_} | ForEach-Object { - if($_ -match '^S-1-.*') { - $_ - } - else { - # if there are any plain group names, try to resolve them to sids - (Convert-NameToSid -ObjectName $_ -Domain $Domain).SID - } - } | Sort-Object -Unique - } + if ($GPO.members) { + $GPO.members = $GPO.members | Where-Object {$_} | ForEach-Object { + if($_ -match '^S-1-.*') { + $_ + } + else { + # if there are any plain group names, try to resolve them to sids + (Convert-NameToSid -ObjectName $_ -Domain $Domain).SID + } + } | Sort-Object -Unique + } - $GPO.members | Foreach-Object { + $GPO.members | ForEach-Object { - # resolve this SID to a domain object - $Object = Get-ADObject -Domain $Domain -DomainController $DomainController -PageSize $PageSize -SID $_ + # resolve this SID to a domain object + $Object = Get-ADObject -Domain $Domain -DomainController $DomainController -PageSize $PageSize -SID $_ - $IsGroup = @('268435456','268435457','536870912','536870913') -contains $Object.samaccounttype + $IsGroup = @('268435456','268435457','536870912','536870913') -contains $Object.samaccounttype - $GPOComputerAdmin = New-Object PSObject - $GPOComputerAdmin | Add-Member Noteproperty 'ComputerName' $ComputerName - $GPOComputerAdmin | Add-Member Noteproperty 'OU' $OU - $GPOComputerAdmin | Add-Member Noteproperty 'GPODisplayName' $GPO.GPODisplayName - $GPOComputerAdmin | Add-Member Noteproperty 'GPOPath' $GPO.GPOPath - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectName' $Object.samaccountname - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectDN' $Object.distinguishedname - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectSID' $_ - $GPOComputerAdmin | Add-Member Noteproperty 'IsGroup' $IsGroup - $GPOComputerAdmin + $GPOComputerAdmin = New-Object PSObject + $GPOComputerAdmin | Add-Member Noteproperty 'ComputerName' $ComputerName + $GPOComputerAdmin | Add-Member Noteproperty 'GPODisplayName' $GPO.GPODisplayName + $GPOComputerAdmin | Add-Member Noteproperty 'GPOPath' $GPO.GPOPath + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectName' $Object.samaccountname + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectDN' $Object.distinguishedname + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectSID' $_ + $GPOComputerAdmin | Add-Member Noteproperty 'IsGroup' $IsGroup + $GPOComputerAdmin - # if we're recursing and the current result object is a group - if($Recurse -and $GPOComputerAdmin.isGroup) { + # if we're recursing and the current result object is a group + if($Recurse -and $GPOComputerAdmin.isGroup) { - Get-NetGroupMember -Domain $Domain -DomainController $DomainController -SID $_ -FullData -Recurse -PageSize $PageSize | Foreach-Object { + Get-NetGroupMember -Domain $Domain -DomainController $DomainController -SID $_ -FullData -Recurse -PageSize $PageSize | ForEach-Object { - $MemberDN = $_.distinguishedName + $MemberDN = $_.distinguishedName - # extract the FQDN from the Distinguished Name - $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.' + # extract the FQDN from the Distinguished Name + $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.' - $MemberIsGroup = @('268435456','268435457','536870912','536870913') -contains $_.samaccounttype + $MemberIsGroup = @('268435456','268435457','536870912','536870913') -contains $_.samaccounttype - if ($_.samAccountName) { - # forest users have the samAccountName set - $MemberName = $_.samAccountName + if ($_.samAccountName) { + # forest users have the samAccountName set + $MemberName = $_.samAccountName + } + else { + # external trust users have a SID, so convert it + try { + $MemberName = Convert-SidToName $_.cn } - else { - # external trust users have a SID, so convert it - try { - $MemberName = Convert-SidToName $_.cn - } - catch { - # if there's a problem contacting the domain to resolve the SID - $MemberName = $_.cn - } + catch { + # if there's a problem contacting the domain to resolve the SID + $MemberName = $_.cn } - - $GPOComputerAdmin = New-Object PSObject - $GPOComputerAdmin | Add-Member Noteproperty 'ComputerName' $ComputerName - $GPOComputerAdmin | Add-Member Noteproperty 'OU' $OU - $GPOComputerAdmin | Add-Member Noteproperty 'GPODisplayName' $GPO.GPODisplayName - $GPOComputerAdmin | Add-Member Noteproperty 'GPOPath' $GPO.GPOPath - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectName' $MemberName - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectDN' $MemberDN - $GPOComputerAdmin | Add-Member Noteproperty 'ObjectSID' $_.objectsid - $GPOComputerAdmin | Add-Member Noteproperty 'IsGroup' $MemberIsGroup - $GPOComputerAdmin } + + $GPOComputerAdmin = New-Object PSObject + $GPOComputerAdmin | Add-Member Noteproperty 'ComputerName' $ComputerName + $GPOComputerAdmin | Add-Member Noteproperty 'GPODisplayName' $GPO.GPODisplayName + $GPOComputerAdmin | Add-Member Noteproperty 'GPOPath' $GPO.GPOPath + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectName' $MemberName + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectDN' $MemberDN + $GPOComputerAdmin | Add-Member Noteproperty 'ObjectSID' $_.objectsid + $GPOComputerAdmin | Add-Member Noteproperty 'IsGroup' $MemberIsGroup + $GPOComputerAdmin } } } @@ -6521,9 +6822,15 @@ function Get-DomainPolicy { .EXAMPLE - PS C:\> Get-NetGPO + PS C:\> Get-DomainPolicy + + Returns the domain policy for the current domain. + + .EXAMPLE - Returns the GPOs in the current domain. + PS C:\> Get-DomainPolicy -Source DC -DomainController MASTER.testlab.local + + Returns the policy for the MASTER.testlab.local domain controller. #> [CmdletBinding()] @@ -6577,25 +6884,25 @@ function Get-DomainPolicy { } # parse the GptTmpl.inf - Get-GptTmpl @ParseArgs | Foreach-Object { + Get-GptTmpl @ParseArgs | ForEach-Object { if($ResolveSids) { # if we're resolving sids in PrivilegeRights to names $Policy = New-Object PSObject - $_.psobject.properties | Foreach-Object { + $_.psobject.properties | ForEach-Object { if( $_.Name -eq 'PrivilegeRights') { $PrivilegeRights = New-Object PSObject # for every nested SID member of PrivilegeRights, try to # unpack everything and resolve the SIDs as appropriate - $_.Value.psobject.properties | Foreach-Object { + $_.Value.psobject.properties | ForEach-Object { - $Sids = $_.Value | Foreach-Object { + $Sids = $_.Value | ForEach-Object { try { if($_ -isnot [System.Array]) { Convert-SidToName $_ } else { - $_ | Foreach-Object { Convert-SidToName $_ } + $_ | ForEach-Object { Convert-SidToName $_ } } } catch { @@ -6707,7 +7014,7 @@ function Get-NetLocalGroup { [Parameter(ParameterSetName = 'WinNT', Position=0, ValueFromPipeline=$True)] [Alias('HostName')] [String[]] - $ComputerName = 'localhost', + $ComputerName = "$($env:COMPUTERNAMECOMPUTERNAME)", [Parameter(ParameterSetName = 'WinNT')] [Parameter(ParameterSetName = 'API')] @@ -7492,7 +7799,7 @@ filter Invoke-CheckLocalAdminAccess { <# .SYNOPSIS - This function will use the OpenSCManagerW Win32API call to to establish + This function will use the OpenSCManagerW Win32API call to establish a handle to the remote host. If this succeeds, the current user context has local administrator acess to the target. @@ -7566,6 +7873,82 @@ filter Invoke-CheckLocalAdminAccess { } +filter Get-SiteName { +<# + .SYNOPSIS + + This function will use the DsGetSiteName Win32API call to look up the + name of the site where a specified computer resides. + + .PARAMETER ComputerName + + The hostname to look the site up for, default to localhost. + + .EXAMPLE + + PS C:\> Get-SiteName -ComputerName WINDOWS1 + + Returns the site for WINDOWS1.testlab.local. + + .EXAMPLE + + PS C:\> Get-NetComputer | Invoke-CheckLocalAdminAccess + + Returns the sites for every machine in AD. +#> + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline=$True)] + [Alias('HostName')] + [Object[]] + [ValidateNotNullOrEmpty()] + $ComputerName = $Env:ComputerName + ) + + # extract the computer name from whatever object was passed on the pipeline + $Computer = $ComputerName | Get-NameField + + # if we get an IP address, try to resolve the IP to a hostname + if($Computer -match '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$') { + $IPAddress = $Computer + $Computer = [System.Net.Dns]::GetHostByAddress($Computer) + } + else { + $IPAddress = @(Get-IPAddress -ComputerName $Computer)[0].IPAddress + } + + $PtrInfo = [IntPtr]::Zero + + $Result = $Netapi32::DsGetSiteName($Computer, [ref]$PtrInfo) + Write-Debug "Get-SiteName result for $Computer : $Result" + + $ComputerSite = New-Object PSObject + $ComputerSite | Add-Member Noteproperty 'ComputerName' $Computer + $ComputerSite | Add-Member Noteproperty 'IPAddress' $IPAddress + + if ($Result -eq 0) { + $Sitename = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($PtrInfo) + $ComputerSite | Add-Member Noteproperty 'SiteName' $Sitename + } + elseif($Result -eq 1210) { + Write-Verbose "Computername '$Computer' is not in a valid form." + $ComputerSite | Add-Member Noteproperty 'SiteName' 'ERROR' + } + elseif($Result -eq 1919) { + Write-Verbose "Computer '$Computer' is not in a site" + + $ComputerSite | Add-Member Noteproperty 'SiteName' $Null + } + else { + Write-Verbose "Error" + $ComputerSite | Add-Member Noteproperty 'SiteName' 'ERROR' + } + + $Null = $Netapi32::NetApiBufferFree($PtrInfo) + $ComputerSite +} + + filter Get-LastLoggedOn { <# .SYNOPSIS @@ -9173,7 +9556,7 @@ function Invoke-ProcessHunter { else { ForEach ($Domain in $TargetDomains) { Write-Verbose "[*] Querying domain $Domain for users of group '$GroupName'" - $TargetUsers += Get-NetGroupMember -GroupName $GroupName -Domain $Domain -DomainController $DomainController -Credential $Credential| Foreach-Object { + $TargetUsers += Get-NetGroupMember -GroupName $GroupName -Domain $Domain -DomainController $DomainController -Credential $Credential| ForEach-Object { $_.MemberName } } @@ -9510,7 +9893,7 @@ function Invoke-EventHunter { else { ForEach ($Domain in $TargetDomains) { Write-Verbose "[*] Querying domain $Domain for users of group '$GroupName'" - $TargetUsers += Get-NetGroupMember -GroupName $GroupName -Domain $Domain -DomainController $DomainController -Credential $Credential | Foreach-Object { + $TargetUsers += Get-NetGroupMember -GroupName $GroupName -Domain $Domain -DomainController $DomainController -Credential $Credential | ForEach-Object { $_.MemberName } } @@ -11776,7 +12159,7 @@ function Find-ManagedSecurityGroups { #> # Go through the list of security groups on the domain and identify those who have a manager - Get-NetGroup -FullData -Filter '(&(managedBy=*)(groupType:1.2.840.113556.1.4.803:=2147483648))' | Select-Object -Unique distinguishedName,managedBy,cn | Foreach-Object { + Get-NetGroup -FullData -Filter '(&(managedBy=*)(groupType:1.2.840.113556.1.4.803:=2147483648))' | Select-Object -Unique distinguishedName,managedBy,cn | ForEach-Object { # Retrieve the object that the managedBy DN refers to $group_manager = Get-ADObject -ADSPath $_.managedBy | Select-Object cn,distinguishedname,name,samaccounttype,samaccountname @@ -11948,8 +12331,9 @@ $FunctionDefinitions = @( (func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), (func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), (func netapi32 NetLocalGroupGetMembers ([Int]) @([String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), - (func advapi32 ConvertSidToStringSid ([Int]) @([IntPtr], [String].MakeByRefType())), + (func netapi32 DsGetSiteName ([Int]) @([String], [IntPtr].MakeByRefType())), (func netapi32 NetApiBufferFree ([Int]) @([IntPtr])), + (func advapi32 ConvertSidToStringSid ([Int]) @([IntPtr], [String].MakeByRefType())), (func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])), (func advapi32 CloseServiceHandle ([Int]) @([IntPtr])), (func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])), |