diff options
-rwxr-xr-x | Recon/PowerView.ps1 | 190 |
1 files changed, 111 insertions, 79 deletions
diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1 index 27f87c7..c1828c8 100755 --- a/Recon/PowerView.ps1 +++ b/Recon/PowerView.ps1 @@ -9480,6 +9480,11 @@ function Invoke-UserHunter { The maximum concurrent threads to execute. + .PARAMETER Poll + + Continuously poll for sessions for the given duration. Automatically + sets Threads to the number of computers being polled. + .EXAMPLE PS C:\> Invoke-UserHunter -CheckAccess @@ -9534,6 +9539,13 @@ function Invoke-UserHunter { Executes old Invoke-StealthUserHunter functionality, enumerating commonly used servers and checking just sessions for each. + .EXAMPLE + + PS C:\> Invoke-UserHunter -Stealth -StealthSource DC -Poll 3600 -Delay 5 -ShowAll | ? { ! $_.UserName.EndsWith('$') } + + Poll Domain Controllers in parallel for sessions for an hour, waiting five + seconds before querying each DC again and filtering out computer accounts. + .LINK http://blog.harmj0y.net #> @@ -9623,7 +9635,10 @@ function Invoke-UserHunter { [Int] [ValidateRange(1,100)] - $Threads + $Threads, + + [UInt32] + $Poll = 0 ) begin { @@ -9632,9 +9647,6 @@ function Invoke-UserHunter { $DebugPreference = 'Continue' } - # random object for delay - $RandNo = New-Object System.Random - Write-Verbose "[*] Running Invoke-UserHunter with delay of $Delay" ##################################################### @@ -9705,6 +9717,14 @@ function Invoke-UserHunter { } } + if ($Poll -gt 0) { + Write-Verbose "[*] Polling for $Poll seconds. Automatically enabling threaded mode." + if ($ComputerName.Count -gt 100) { + throw "Too many hosts to poll! Try fewer than 100." + } + $Threads = $ComputerName.Count + } + ##################################################### # # Now we build the user target set @@ -9802,7 +9822,7 @@ function Invoke-UserHunter { # script block that enumerates a server $HostEnumBlock = { - param($ComputerName, $Ping, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName) + param($ComputerName, $Ping, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName, $Poll, $Delay, $Jitter) # optionally check if the server is up first $Up = $True @@ -9810,89 +9830,46 @@ function Invoke-UserHunter { $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName } if($Up) { - if(!$DomainShortName) { - # if we're not searching for foreign users, check session information - $Sessions = Get-NetSession -ComputerName $ComputerName - ForEach ($Session in $Sessions) { - $UserName = $Session.sesi10_username - $CName = $Session.sesi10_cname - - if($CName -and $CName.StartsWith("\\")) { - $CName = $CName.TrimStart("\") - } - - # make sure we have a result - if (($UserName) -and ($UserName.trim() -ne '') -and (!($UserName -match $CurrentUser))) { - - $TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object { - - $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress - $FoundUser = New-Object PSObject - $FoundUser | Add-Member Noteproperty 'UserDomain' $_.MemberDomain - $FoundUser | Add-Member Noteproperty 'UserName' $UserName - $FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName - $FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress - $FoundUser | Add-Member Noteproperty 'SessionFrom' $CName - - # Try to resolve the DNS hostname of $Cname - try { - $CNameDNSName = [System.Net.Dns]::GetHostEntry($CName) | Select-Object -ExpandProperty HostName - $FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName - } - catch { - $FoundUser | Add-Member NoteProperty 'SessionFromName' $Null - } - - # see if we're checking to see if we have local admin access on this machine - if ($CheckAccess) { - $Admin = Invoke-CheckLocalAdminAccess -ComputerName $CName - $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin - } - else { - $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null - } - $FoundUser.PSObject.TypeNames.Add('PowerView.UserSession') - $FoundUser + $Timer = [System.Diagnostics.Stopwatch]::StartNew() + $RandNo = New-Object System.Random + + Do { + if(!$DomainShortName) { + # if we're not searching for foreign users, check session information + $Sessions = Get-NetSession -ComputerName $ComputerName + ForEach ($Session in $Sessions) { + $UserName = $Session.sesi10_username + $CName = $Session.sesi10_cname + + if($CName -and $CName.StartsWith("\\")) { + $CName = $CName.TrimStart("\") } - } - } - } - if(!$Stealth) { - # if we're not 'stealthy', enumerate loggedon users as well - $LoggedOn = Get-NetLoggedon -ComputerName $ComputerName - ForEach ($User in $LoggedOn) { - $UserName = $User.wkui1_username - # TODO: translate domain to authoratative name - # then match domain name ? - $UserDomain = $User.wkui1_logon_domain - # make sure wet have a result - if (($UserName) -and ($UserName.trim() -ne '')) { + # make sure we have a result + if (($UserName) -and ($UserName.trim() -ne '') -and (!($UserName -match $CurrentUser))) { - $TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object { + $TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object { - $Proceed = $True - if($DomainShortName) { - if ($DomainShortName.ToLower() -ne $UserDomain.ToLower()) { - $Proceed = $True - } - else { - $Proceed = $False - } - } - if($Proceed) { $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress $FoundUser = New-Object PSObject - $FoundUser | Add-Member Noteproperty 'UserDomain' $UserDomain + $FoundUser | Add-Member Noteproperty 'UserDomain' $_.MemberDomain $FoundUser | Add-Member Noteproperty 'UserName' $UserName $FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName $FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress - $FoundUser | Add-Member Noteproperty 'SessionFrom' $Null - $FoundUser | Add-Member Noteproperty 'SessionFromName' $Null + $FoundUser | Add-Member Noteproperty 'SessionFrom' $CName + + # Try to resolve the DNS hostname of $Cname + try { + $CNameDNSName = [System.Net.Dns]::GetHostEntry($CName) | Select-Object -ExpandProperty HostName + $FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName + } + catch { + $FoundUser | Add-Member NoteProperty 'SessionFromName' $Null + } # see if we're checking to see if we have local admin access on this machine if ($CheckAccess) { - $Admin = Invoke-CheckLocalAdminAccess -ComputerName $ComputerName + $Admin = Invoke-CheckLocalAdminAccess -ComputerName $CName $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin } else { @@ -9904,10 +9881,61 @@ function Invoke-UserHunter { } } } - } + if(!$Stealth) { + # if we're not 'stealthy', enumerate loggedon users as well + $LoggedOn = Get-NetLoggedon -ComputerName $ComputerName + ForEach ($User in $LoggedOn) { + $UserName = $User.wkui1_username + # TODO: translate domain to authoratative name + # then match domain name ? + $UserDomain = $User.wkui1_logon_domain + + # make sure wet have a result + if (($UserName) -and ($UserName.trim() -ne '')) { + + $TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object { + + $Proceed = $True + if($DomainShortName) { + if ($DomainShortName.ToLower() -ne $UserDomain.ToLower()) { + $Proceed = $True + } + else { + $Proceed = $False + } + } + if($Proceed) { + $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress + $FoundUser = New-Object PSObject + $FoundUser | Add-Member Noteproperty 'UserDomain' $UserDomain + $FoundUser | Add-Member Noteproperty 'UserName' $UserName + $FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName + $FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress + $FoundUser | Add-Member Noteproperty 'SessionFrom' $Null + $FoundUser | Add-Member Noteproperty 'SessionFromName' $Null + + # see if we're checking to see if we have local admin access on this machine + if ($CheckAccess) { + $Admin = Invoke-CheckLocalAdminAccess -ComputerName $ComputerName + $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin + } + else { + $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null + } + $FoundUser.PSObject.TypeNames.Add('PowerView.UserSession') + $FoundUser + } + } + } + } + } + + if ($Poll -gt 0) { + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + } + } While ($Poll -gt 0 -and $Timer.Elapsed.TotalSeconds -lt $Poll) } } - } process { @@ -9922,6 +9950,9 @@ function Invoke-UserHunter { 'CurrentUser' = $CurrentUser 'Stealth' = $Stealth 'DomainShortName' = $DomainShortName + 'Poll' = $Poll + 'Delay' = $Delay + 'Jitter' = $Jitter } # kick off the threaded script block + arguments @@ -9937,6 +9968,7 @@ function Invoke-UserHunter { Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)" $Counter = 0 + $RandNo = New-Object System.Random ForEach ($Computer in $ComputerName) { @@ -9946,7 +9978,7 @@ function Invoke-UserHunter { Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))" - $Result = Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName + $Result = Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName, 0, 0, 0 $Result if($Result -and $StopOnSuccess) { |