aboutsummaryrefslogtreecommitdiff
path: root/Recon/PowerView.ps1
diff options
context:
space:
mode:
authorHarmj0y <will@harmj0y.net>2016-03-07 02:00:00 -0500
committerHarmj0y <will@harmj0y.net>2016-03-07 02:00:00 -0500
commitb4891eb371c83c0eef7cc3d4485b3a7066c9641e (patch)
tree06f66ac9106267b898c0ef0955b2c6750a9fe528 /Recon/PowerView.ps1
parent26ca1a922e6f2ca08b265ab43a36eefc4bc6acbe (diff)
downloadPowerSploit-b4891eb371c83c0eef7cc3d4485b3a7066c9641e.tar.gz
PowerSploit-b4891eb371c83c0eef7cc3d4485b3a7066c9641e.zip
Added NetLocalGroupGetMembers enumeration method for Get-NetLocalGroup with the -API flag
Fixed threading specification in most threaded functions.
Diffstat (limited to 'Recon/PowerView.ps1')
-rw-r--r--Recon/PowerView.ps1453
1 files changed, 302 insertions, 151 deletions
diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1
index d07edf6..7d6f819 100644
--- a/Recon/PowerView.ps1
+++ b/Recon/PowerView.ps1
@@ -6570,6 +6570,11 @@ function Get-NetLocalGroup {
Switch. If the local member member is a domain group, recursively try to resolve its members to get a list of domain users who can access this machine.
+ .PARAMETER API
+
+ Switch. Use API calls instead of the WinNT service provider. Less information,
+ but the results are faster.
+
.EXAMPLE
PS C:\> Get-NetLocalGroup
@@ -6595,42 +6600,52 @@ function Get-NetLocalGroup {
Returns all local groups on the WINDOWS7 host.
+ .EXAMPLE
+
+ PS C:\> "WINDOWS7", "WINDOWSSP" | Get-NetLocalGroup -API
+
+ Returns all local groups on the the passed hosts using API calls instead of the
+ WinNT service provider.
+
.LINK
http://stackoverflow.com/questions/21288220/get-all-local-members-and-groups-displayed-together
http://msdn.microsoft.com/en-us/library/aa772211(VS.85).aspx
#>
- [CmdletBinding()]
+ [CmdletBinding(DefaultParameterSetName = 'WinNT')]
param(
- [Parameter(ValueFromPipeline=$True)]
+ [Parameter(ParameterSetName = 'API', Position=0, ValueFromPipeline=$True)]
+ [Parameter(ParameterSetName = 'WinNT', Position=0, ValueFromPipeline=$True)]
[Alias('HostName')]
[String[]]
$ComputerName = 'localhost',
+ [Parameter(ParameterSetName = 'WinNT')]
+ [Parameter(ParameterSetName = 'API')]
[ValidateScript({Test-Path -Path $_ })]
[Alias('HostList')]
[String]
$ComputerFile,
+ [Parameter(ParameterSetName = 'WinNT')]
+ [Parameter(ParameterSetName = 'API')]
[String]
- $GroupName,
+ $GroupName = 'Administrators',
+ [Parameter(ParameterSetName = 'WinNT')]
[Switch]
$ListGroups,
+ [Parameter(ParameterSetName = 'WinNT')]
[Switch]
- $Recurse
+ $Recurse,
+
+ [Parameter(ParameterSetName = 'API')]
+ [Switch]
+ $API
)
- begin {
- if ((-not $ListGroups) -and (-not $GroupName)) {
- # resolve the SID for the local admin group - this should usually default to "Administrators"
- $ObjSID = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
- $Objgroup = $ObjSID.Translate( [System.Security.Principal.NTAccount])
- $GroupName = ($Objgroup.Value).Split('\')[1]
- }
- }
process {
$Servers = @()
@@ -6647,168 +6662,262 @@ function Get-NetLocalGroup {
# query the specified group using the WINNT provider, and
# extract fields as appropriate from the results
ForEach($Server in $Servers) {
- try {
- if($ListGroups) {
- # if we're listing the group names on a remote server
- $Computer = [ADSI]"WinNT://$Server,computer"
-
- $Computer.psbase.children | Where-Object { $_.psbase.schemaClassName -eq 'group' } | ForEach-Object {
- $Group = New-Object PSObject
- $Group | Add-Member Noteproperty 'Server' $Server
- $Group | Add-Member Noteproperty 'Group' ($_.name[0])
- $Group | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier $_.objectsid[0],0).Value)
- $Group | Add-Member Noteproperty 'Description' ($_.Description[0])
- $Group
- }
- }
- else {
- # otherwise we're listing the group members
- $Members = @($([ADSI]"WinNT://$Server/$GroupName,group").psbase.Invoke('Members'))
- $Members | ForEach-Object {
+ if($API) {
+ # if we're using the Netapi32 NetLocalGroupGetMembers API call to
+ # get the local group information
+
+ # arguments for NetLocalGroupGetMembers
+ $QueryLevel = 2
+ $PtrInfo = [IntPtr]::Zero
+ $EntriesRead = 0
+ $TotalRead = 0
+ $ResumeHandle = 0
+
+ # get the local user information
+ $Result = $Netapi32::NetLocalGroupGetMembers($Server, $GroupName, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
+
+ # Locate the offset of the initial intPtr
+ $Offset = $PtrInfo.ToInt64()
+
+ Write-Debug "NetLocalGroupGetMembers result for $Server : $Result"
+ $LocalUsers = @()
+
+ # 0 = success
+ if (($Result -eq 0) -and ($Offset -gt 0)) {
- $Member = New-Object PSObject
- $Member | Add-Member Noteproperty 'ComputerName' $Server
+ # Work out how mutch to increment the pointer by finding out the size of the structure
+ $Increment = $LOCALGROUP_MEMBERS_INFO_2::GetSize()
- $AdsPath = ($_.GetType().InvokeMember('Adspath', 'GetProperty', $Null, $_, $Null)).Replace('WinNT://', '')
+ # parse all the result structures
+ for ($i = 0; ($i -lt $EntriesRead); $i++) {
+ # create a new int ptr at the given offset and cast
+ # the pointer as our result structure
+ $NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
+ $Info = $NewIntPtr -as $LOCALGROUP_MEMBERS_INFO_2
- # try to translate the NT4 domain to a FQDN if possible
- $Name = Convert-NT4toCanonical -ObjectName $AdsPath
- if($Name) {
- $FQDN = $Name.split("/")[0]
- $ObjName = $AdsPath.split("/")[-1]
- $Name = "$FQDN/$ObjName"
- $IsDomain = $True
+ $SidString = ""
+ $Result = $Advapi32::ConvertSidToStringSid($Info.lgrmi2_sid, [ref]$SidString)
+ Write-Debug "Result of ConvertSidToStringSid: $Result"
+
+ if($Result -eq 0) {
+ # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
+ $Err = $Kernel32::GetLastError()
+ Write-Error "ConvertSidToStringSid LastError: $Err"
}
else {
- $Name = $AdsPath
- $IsDomain = $False
- }
+ $LocalUser = New-Object PSObject
+ $LocalUser | Add-Member Noteproperty 'ComputerName' $Server
+ $LocalUser | Add-Member Noteproperty 'MemberName' $Info.lgrmi2_domainandname
+ $LocalUser | Add-Member Noteproperty 'SID' $SidString
+ $LocalUser | Add-Member Noteproperty 'SidType' $Info.lgrmi2_sidusage
- $Member | Add-Member Noteproperty 'AccountName' $Name
+ $Offset = $NewIntPtr.ToInt64()
+ $Offset += $Increment
- if($IsDomain) {
- # translate the binary sid to a string
- $Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($_.GetType().InvokeMember('ObjectSID', 'GetProperty', $Null, $_, $Null),0)).Value)
+ $LocalUsers += $LocalUser
+ }
+ }
- $Member | Add-Member Noteproperty 'Description' ""
- $Member | Add-Member Noteproperty 'Disabled' $False
+ # free up the result buffer
+ $Null = $Netapi32::NetApiBufferFree($PtrInfo)
- # check if the member is a group
- $IsGroup = ($_.GetType().InvokeMember('Class', 'GetProperty', $Null, $_, $Null) -eq 'group')
- $Member | Add-Member Noteproperty 'IsGroup' $IsGroup
- $Member | Add-Member Noteproperty 'IsDomain' $IsDomain
+ # try to extract out the machine SID by using the -500 account as a reference
+ $MachineSid = $LocalUsers | Where-Object {$_.SID -like '*-500'}
+ $Parts = $MachineSid.SID.Split('-')
+ $MachineSid = $Parts[0..($Parts.Length -2)] -join '-'
- if($IsGroup) {
- $Member | Add-Member Noteproperty 'LastLogin' $Null
- }
- else {
- try {
- $Member | Add-Member Noteproperty 'LastLogin' ( $_.GetType().InvokeMember('LastLogin', 'GetProperty', $Null, $_, $Null))
- }
- catch {
- $Member | Add-Member Noteproperty 'LastLogin' $Null
- }
- }
- $Member | Add-Member Noteproperty 'PwdLastSet' ""
- $Member | Add-Member Noteproperty 'PwdExpired' ""
- $Member | Add-Member Noteproperty 'UserFlags' ""
+ $LocalUsers | ForEach-Object {
+ if($_.SID -match $MachineSid) {
+ $_ | Add-Member Noteproperty 'IsDomain' $False
}
else {
- # repull this user object so we can ensure correct information
- $LocalUser = $([ADSI] "WinNT://$AdsPath")
+ $_ | Add-Member Noteproperty 'IsDomain' $True
+ }
+ }
+ $LocalUsers
+ }
+ else
+ {
+ switch ($Result) {
+ (5) {Write-Debug 'The user does not have access to the requested information.'}
+ (124) {Write-Debug 'The value specified for the level parameter is not valid.'}
+ (87) {Write-Debug 'The specified parameter is not valid.'}
+ (234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
+ (8) {Write-Debug 'Insufficient memory is available.'}
+ (2312) {Write-Debug 'A session does not exist with the computer name.'}
+ (2351) {Write-Debug 'The computer name is not valid.'}
+ (2221) {Write-Debug 'Username not found.'}
+ (53) {Write-Debug 'Hostname could not be found'}
+ }
+ }
+ }
- # translate the binary sid to a string
- $Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($LocalUser.objectSid.value,0)).Value)
+ else {
+ # otherwise we're using the WinNT service provider
+ try {
+ if($ListGroups) {
+ # if we're listing the group names on a remote server
+ $Computer = [ADSI]"WinNT://$Server,computer"
+
+ $Computer.psbase.children | Where-Object { $_.psbase.schemaClassName -eq 'group' } | ForEach-Object {
+ $Group = New-Object PSObject
+ $Group | Add-Member Noteproperty 'Server' $Server
+ $Group | Add-Member Noteproperty 'Group' ($_.name[0])
+ $Group | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier $_.objectsid[0],0).Value)
+ $Group | Add-Member Noteproperty 'Description' ($_.Description[0])
+ $Group
+ }
+ }
+ else {
+ # otherwise we're listing the group members
+ $Members = @($([ADSI]"WinNT://$Server/$GroupName,group").psbase.Invoke('Members'))
- $Member | Add-Member Noteproperty 'Description' ($LocalUser.Description[0])
+ $Members | ForEach-Object {
- # UAC flags of 0x2 mean the account is disabled
- $Member | Add-Member Noteproperty 'Disabled' $(($LocalUser.userFlags.value -band 2) -eq 2)
+ $Member = New-Object PSObject
+ $Member | Add-Member Noteproperty 'ComputerName' $Server
- # check if the member is a group
- $Member | Add-Member Noteproperty 'IsGroup' ($LocalUser.SchemaClassName -like 'group')
- $Member | Add-Member Noteproperty 'IsDomain' $IsDomain
+ $AdsPath = ($_.GetType().InvokeMember('Adspath', 'GetProperty', $Null, $_, $Null)).Replace('WinNT://', '')
- if($IsGroup) {
- $Member | Add-Member Noteproperty 'LastLogin' ""
+ # try to translate the NT4 domain to a FQDN if possible
+ $Name = Convert-NT4toCanonical -ObjectName $AdsPath
+ if($Name) {
+ $FQDN = $Name.split("/")[0]
+ $ObjName = $AdsPath.split("/")[-1]
+ $Name = "$FQDN/$ObjName"
+ $IsDomain = $True
}
else {
- try {
- $Member | Add-Member Noteproperty 'LastLogin' ( $LocalUser.LastLogin[0])
- }
- catch {
- $Member | Add-Member Noteproperty 'LastLogin' ""
- }
+ $Name = $AdsPath
+ $IsDomain = $False
}
- $Member | Add-Member Noteproperty 'PwdLastSet' ( (Get-Date).AddSeconds(-$LocalUser.PasswordAge[0]))
- $Member | Add-Member Noteproperty 'PwdExpired' ( $LocalUser.PasswordExpired[0] -eq '1')
- $Member | Add-Member Noteproperty 'UserFlags' ( $LocalUser.UserFlags[0] )
- }
- $Member
-
- # if the result is a group domain object and we're recursing,
- # try to resolve all the group member results
- if($Recurse -and $IsDomain -and $IsGroup) {
+ $Member | Add-Member Noteproperty 'AccountName' $Name
- $FQDN = $Name.split("/")[0]
- $GroupName = $Name.split("/")[1].trim()
+ if($IsDomain) {
+ # translate the binary sid to a string
+ $Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($_.GetType().InvokeMember('ObjectSID', 'GetProperty', $Null, $_, $Null),0)).Value)
- Get-NetGroupMember -GroupName $GroupName -Domain $FQDN -FullData -Recurse | ForEach-Object {
-
- $Member = New-Object PSObject
- $Member | Add-Member Noteproperty 'ComputerName' "$FQDN/$($_.GroupName)"
+ $Member | Add-Member Noteproperty 'Description' ""
+ $Member | Add-Member Noteproperty 'Disabled' $False
- $MemberDN = $_.distinguishedName
- # extract the FQDN from the Distinguished Name
- $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
+ # check if the member is a group
+ $IsGroup = ($_.GetType().InvokeMember('Class', 'GetProperty', $Null, $_, $Null) -eq 'group')
+ $Member | Add-Member Noteproperty 'IsGroup' $IsGroup
+ $Member | Add-Member Noteproperty 'IsDomain' $IsDomain
- if ($_.samAccountType -ne "805306368") {
- $MemberIsGroup = $True
+ if($IsGroup) {
+ $Member | Add-Member Noteproperty 'LastLogin' $Null
}
else {
- $MemberIsGroup = $False
+ try {
+ $Member | Add-Member Noteproperty 'LastLogin' ( $_.GetType().InvokeMember('LastLogin', 'GetProperty', $Null, $_, $Null))
+ }
+ catch {
+ $Member | Add-Member Noteproperty 'LastLogin' $Null
+ }
}
+ $Member | Add-Member Noteproperty 'PwdLastSet' ""
+ $Member | Add-Member Noteproperty 'PwdExpired' ""
+ $Member | Add-Member Noteproperty 'UserFlags' ""
+ }
+ else {
+ # repull this user object so we can ensure correct information
+ $LocalUser = $([ADSI] "WinNT://$AdsPath")
+
+ # translate the binary sid to a string
+ $Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($LocalUser.objectSid.value,0)).Value)
+
+ $Member | Add-Member Noteproperty 'Description' ($LocalUser.Description[0])
+
+ # UAC flags of 0x2 mean the account is disabled
+ $Member | Add-Member Noteproperty 'Disabled' $(($LocalUser.userFlags.value -band 2) -eq 2)
- if ($_.samAccountName) {
- # forest users have the samAccountName set
- $MemberName = $_.samAccountName
+ # check if the member is a group
+ $Member | Add-Member Noteproperty 'IsGroup' ($LocalUser.SchemaClassName -like 'group')
+ $Member | Add-Member Noteproperty 'IsDomain' $IsDomain
+
+ if($IsGroup) {
+ $Member | Add-Member Noteproperty 'LastLogin' ""
}
else {
try {
- # external trust users have a SID, so convert it
+ $Member | Add-Member Noteproperty 'LastLogin' ( $LocalUser.LastLogin[0])
+ }
+ catch {
+ $Member | Add-Member Noteproperty 'LastLogin' ""
+ }
+ }
+
+ $Member | Add-Member Noteproperty 'PwdLastSet' ( (Get-Date).AddSeconds(-$LocalUser.PasswordAge[0]))
+ $Member | Add-Member Noteproperty 'PwdExpired' ( $LocalUser.PasswordExpired[0] -eq '1')
+ $Member | Add-Member Noteproperty 'UserFlags' ( $LocalUser.UserFlags[0] )
+ }
+ $Member
+
+ # if the result is a group domain object and we're recursing,
+ # try to resolve all the group member results
+ if($Recurse -and $IsDomain -and $IsGroup) {
+
+ $FQDN = $Name.split("/")[0]
+ $GroupName = $Name.split("/")[1].trim()
+
+ Get-NetGroupMember -GroupName $GroupName -Domain $FQDN -FullData -Recurse | ForEach-Object {
+
+ $Member = New-Object PSObject
+ $Member | Add-Member Noteproperty 'ComputerName' "$FQDN/$($_.GroupName)"
+
+ $MemberDN = $_.distinguishedName
+ # extract the FQDN from the Distinguished Name
+ $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
+
+ if ($_.samAccountType -ne "805306368") {
+ $MemberIsGroup = $True
+ }
+ else {
+ $MemberIsGroup = $False
+ }
+
+ if ($_.samAccountName) {
+ # forest users have the samAccountName set
+ $MemberName = $_.samAccountName
+ }
+ else {
try {
- $MemberName = Convert-SidToName $_.cn
+ # 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
+ Write-Debug "Error resolving SID : $_"
}
}
- catch {
- Write-Debug "Error resolving SID : $_"
- }
- }
- $Member | Add-Member Noteproperty 'AccountName' "$MemberDomain/$MemberName"
- $Member | Add-Member Noteproperty 'SID' $_.objectsid
- $Member | Add-Member Noteproperty 'Description' $_.description
- $Member | Add-Member Noteproperty 'Disabled' $False
- $Member | Add-Member Noteproperty 'IsGroup' $MemberIsGroup
- $Member | Add-Member Noteproperty 'IsDomain' $True
- $Member | Add-Member Noteproperty 'LastLogin' ''
- $Member | Add-Member Noteproperty 'PwdLastSet' $_.pwdLastSet
- $Member | Add-Member Noteproperty 'PwdExpired' ''
- $Member | Add-Member Noteproperty 'UserFlags' $_.userAccountControl
- $Member
+ $Member | Add-Member Noteproperty 'AccountName' "$MemberDomain/$MemberName"
+ $Member | Add-Member Noteproperty 'SID' $_.objectsid
+ $Member | Add-Member Noteproperty 'Description' $_.description
+ $Member | Add-Member Noteproperty 'Disabled' $False
+ $Member | Add-Member Noteproperty 'IsGroup' $MemberIsGroup
+ $Member | Add-Member Noteproperty 'IsDomain' $True
+ $Member | Add-Member Noteproperty 'LastLogin' ''
+ $Member | Add-Member Noteproperty 'PwdLastSet' $_.pwdLastSet
+ $Member | Add-Member Noteproperty 'PwdExpired' ''
+ $Member | Add-Member Noteproperty 'UserFlags' $_.userAccountControl
+ $Member
+ }
}
}
}
}
- }
- catch {
- Write-Warning "[!] Error: $_"
+ catch {
+ Write-Warning "[!] Error: $_"
+ }
}
}
}
@@ -7288,7 +7397,7 @@ filter Get-NetRDPSession {
# otherwise it failed - get the last error
# error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
$Err = $Kernel32::GetLastError()
- Write-Verbuse "LastError: $Err"
+ Write-Verbose "LastError: $Err"
}
}
@@ -8580,7 +8689,7 @@ function Invoke-UserHunter {
}
# kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -9036,7 +9145,7 @@ function Invoke-ProcessHunter {
}
# kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -9367,7 +9476,7 @@ function Invoke-EventHunter {
}
# kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -9684,7 +9793,7 @@ function Invoke-ShareFinder {
}
# kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -10164,10 +10273,10 @@ function Invoke-FileFinder {
# kick off the threaded script block + arguments
if($Shares) {
# pass the shares as the hosts so the threaded function code doesn't have to be hacked up
- Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
}
@@ -10416,7 +10525,7 @@ function Find-LocalAdminAccess {
}
# kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -10848,6 +10957,11 @@ function Invoke-EnumerateLocalAdmin {
Switch. Search all domains in the forest for target users instead of just
a single domain.
+ .PARAMETER API
+
+ Switch. Use API calls instead of the WinNT service provider. Less information,
+ but the results are faster.
+
.PARAMETER Threads
The maximum concurrent threads to execute.
@@ -10917,7 +11031,10 @@ function Invoke-EnumerateLocalAdmin {
[ValidateRange(1,100)]
[Int]
- $Threads
+ $Threads,
+
+ [Switch]
+ $API
)
begin {
@@ -10986,7 +11103,7 @@ function Invoke-EnumerateLocalAdmin {
# script block that enumerates a server
$HostEnumBlock = {
- param($ComputerName, $Ping, $OutFile, $DomainSID, $TrustGroupsSIDs)
+ param($ComputerName, $Ping, $OutFile, $DomainSID, $TrustGroupsSIDs, $API)
# optionally check if the server is up first
$Up = $True
@@ -10995,7 +11112,12 @@ function Invoke-EnumerateLocalAdmin {
}
if($Up) {
# grab the users for the local admins on this server
- $LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName
+ if($API) {
+ $LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName -API
+ }
+ else {
+ $LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName
+ }
# if we just want to return cross-trust users
if($DomainSID -and $TrustGroupSIDS) {
@@ -11038,8 +11160,12 @@ function Invoke-EnumerateLocalAdmin {
'TrustGroupsSIDs' = $TrustGroupsSIDs
}
- # kick off the threaded script block + arguments
- Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
+ # kick off the threaded script block + arguments
+ if($API) {
+ $ScriptParams['API'] = $True
+ }
+
+ Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
}
else {
@@ -11058,9 +11184,14 @@ function Invoke-EnumerateLocalAdmin {
# sleep for our semi-randomized interval
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
-
Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
- Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs
+
+ if($API) {
+ Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs, $True
+ }
+ else {
+ Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs
+ }
}
}
}
@@ -11512,6 +11643,7 @@ function Find-ForeignGroup {
}
}
+
function Find-ManagedSecurityGroups {
<#
.SYNOPSIS
@@ -11577,13 +11709,11 @@ function Find-ManagedSecurityGroups {
if ($xacl.ObjectType -eq 'bf9679c0-0de6-11d0-a285-00aa003049e2' -and $xacl.AccessControlType -eq 'Allow' -and $xacl.IdentityReference.Value.Contains($group_manager.samaccountname)) {
$results_object.CanManagerWrite = $TRUE
}
-
$results_object
-
}
-
}
+
function Invoke-MapDomainTrust {
<#
.SYNOPSIS
@@ -11720,11 +11850,13 @@ $FunctionDefinitions = @(
(func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(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 NetApiBufferFree ([Int]) @([IntPtr])),
(func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])),
(func advapi32 CloseServiceHandle ([Int]) @([IntPtr])),
(func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])),
- (func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
+ (func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])),
(func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])),
@@ -11787,10 +11919,29 @@ $SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
sesi10_idle_time = field 3 UInt32
}
+# enum used by $LOCALGROUP_MEMBERS_INFO_2 below
+$SID_NAME_USE = psenum $Mod SID_NAME_USE UInt16 @{
+ SidTypeUser = 1
+ SidTypeGroup = 2
+ SidTypeDomain = 3
+ SidTypeAlias = 4
+ SidTypeWellKnownGroup = 5
+ SidTypeDeletedAccount = 6
+ SidTypeInvalid = 7
+ SidTypeUnknown = 8
+ SidTypeComputer = 9
+}
+
+# the NetLocalGroupGetMembers result structure
+$LOCALGROUP_MEMBERS_INFO_2 = struct $Mod LOCALGROUP_MEMBERS_INFO_2 @{
+ lgrmi2_sid = field 0 IntPtr
+ lgrmi2_sidusage = field 1 $SID_NAME_USE
+ lgrmi2_domainandname = field 2 String -MarshalAs @('LPWStr')
+}
+
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Netapi32 = $Types['netapi32']
$Advapi32 = $Types['advapi32']
$Kernel32 = $Types['kernel32']
$Wtsapi32 = $Types['wtsapi32']
-