Skip to content
This repository was archived by the owner on Jan 21, 2021. It is now read-only.

Commit fda4563

Browse files
author
Jon Cave
committed
Add a polling mode to Invoke-UserHunter
Repeatedly poll a set of target computers for user sessions. This could be a useful technique for building a much better picture of current sessions, but without having to communicate with every host. The -Poll parameter is used to specify the duration for which polling should occur. Each target computer is dedicated with a thread with -Delay and -Jitter specifying how long to sleep between each session enumeration attempt of an individual host.
1 parent 869badc commit fda4563

File tree

1 file changed

+111
-79
lines changed

1 file changed

+111
-79
lines changed

Recon/PowerView.ps1

Lines changed: 111 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -9480,6 +9480,11 @@ function Invoke-UserHunter {
94809480
94819481
The maximum concurrent threads to execute.
94829482
9483+
.PARAMETER Poll
9484+
9485+
Continuously poll for sessions for the given duration. Automatically
9486+
sets Threads to the number of computers being polled.
9487+
94839488
.EXAMPLE
94849489
94859490
PS C:\> Invoke-UserHunter -CheckAccess
@@ -9534,6 +9539,13 @@ function Invoke-UserHunter {
95349539
Executes old Invoke-StealthUserHunter functionality, enumerating commonly
95359540
used servers and checking just sessions for each.
95369541
9542+
.EXAMPLE
9543+
9544+
PS C:\> Invoke-UserHunter -Stealth -StealthSource DC -Poll 3600 -Delay 5 -ShowAll | ? { ! $_.UserName.EndsWith('$') }
9545+
9546+
Poll Domain Controllers in parallel for sessions for an hour, waiting five
9547+
seconds before querying each DC again and filtering out computer accounts.
9548+
95379549
.LINK
95389550
http://blog.harmj0y.net
95399551
#>
@@ -9623,7 +9635,10 @@ function Invoke-UserHunter {
96239635

96249636
[Int]
96259637
[ValidateRange(1,100)]
9626-
$Threads
9638+
$Threads,
9639+
9640+
[UInt32]
9641+
$Poll = 0
96279642
)
96289643

96299644
begin {
@@ -9632,9 +9647,6 @@ function Invoke-UserHunter {
96329647
$DebugPreference = 'Continue'
96339648
}
96349649

9635-
# random object for delay
9636-
$RandNo = New-Object System.Random
9637-
96389650
Write-Verbose "[*] Running Invoke-UserHunter with delay of $Delay"
96399651

96409652
#####################################################
@@ -9705,6 +9717,14 @@ function Invoke-UserHunter {
97059717
}
97069718
}
97079719

9720+
if ($Poll -gt 0) {
9721+
Write-Verbose "[*] Polling for $Poll seconds. Automatically enabling threaded mode."
9722+
if ($ComputerName.Count -gt 100) {
9723+
throw "Too many hosts to poll! Try fewer than 100."
9724+
}
9725+
$Threads = $ComputerName.Count
9726+
}
9727+
97089728
#####################################################
97099729
#
97109730
# Now we build the user target set
@@ -9802,97 +9822,54 @@ function Invoke-UserHunter {
98029822

98039823
# script block that enumerates a server
98049824
$HostEnumBlock = {
9805-
param($ComputerName, $Ping, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName)
9825+
param($ComputerName, $Ping, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName, $Poll, $Delay, $Jitter)
98069826

98079827
# optionally check if the server is up first
98089828
$Up = $True
98099829
if($Ping) {
98109830
$Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
98119831
}
98129832
if($Up) {
9813-
if(!$DomainShortName) {
9814-
# if we're not searching for foreign users, check session information
9815-
$Sessions = Get-NetSession -ComputerName $ComputerName
9816-
ForEach ($Session in $Sessions) {
9817-
$UserName = $Session.sesi10_username
9818-
$CName = $Session.sesi10_cname
9819-
9820-
if($CName -and $CName.StartsWith("\\")) {
9821-
$CName = $CName.TrimStart("\")
9822-
}
9823-
9824-
# make sure we have a result
9825-
if (($UserName) -and ($UserName.trim() -ne '') -and (!($UserName -match $CurrentUser))) {
9826-
9827-
$TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object {
9828-
9829-
$IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress
9830-
$FoundUser = New-Object PSObject
9831-
$FoundUser | Add-Member Noteproperty 'UserDomain' $_.MemberDomain
9832-
$FoundUser | Add-Member Noteproperty 'UserName' $UserName
9833-
$FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName
9834-
$FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress
9835-
$FoundUser | Add-Member Noteproperty 'SessionFrom' $CName
9836-
9837-
# Try to resolve the DNS hostname of $Cname
9838-
try {
9839-
$CNameDNSName = [System.Net.Dns]::GetHostEntry($CName) | Select-Object -ExpandProperty HostName
9840-
$FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName
9841-
}
9842-
catch {
9843-
$FoundUser | Add-Member NoteProperty 'SessionFromName' $Null
9844-
}
9845-
9846-
# see if we're checking to see if we have local admin access on this machine
9847-
if ($CheckAccess) {
9848-
$Admin = Invoke-CheckLocalAdminAccess -ComputerName $CName
9849-
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin
9850-
}
9851-
else {
9852-
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null
9853-
}
9854-
$FoundUser.PSObject.TypeNames.Add('PowerView.UserSession')
9855-
$FoundUser
9833+
$Timer = [System.Diagnostics.Stopwatch]::StartNew()
9834+
$RandNo = New-Object System.Random
9835+
9836+
Do {
9837+
if(!$DomainShortName) {
9838+
# if we're not searching for foreign users, check session information
9839+
$Sessions = Get-NetSession -ComputerName $ComputerName
9840+
ForEach ($Session in $Sessions) {
9841+
$UserName = $Session.sesi10_username
9842+
$CName = $Session.sesi10_cname
9843+
9844+
if($CName -and $CName.StartsWith("\\")) {
9845+
$CName = $CName.TrimStart("\")
98569846
}
9857-
}
9858-
}
9859-
}
9860-
if(!$Stealth) {
9861-
# if we're not 'stealthy', enumerate loggedon users as well
9862-
$LoggedOn = Get-NetLoggedon -ComputerName $ComputerName
9863-
ForEach ($User in $LoggedOn) {
9864-
$UserName = $User.wkui1_username
9865-
# TODO: translate domain to authoratative name
9866-
# then match domain name ?
9867-
$UserDomain = $User.wkui1_logon_domain
98689847

9869-
# make sure wet have a result
9870-
if (($UserName) -and ($UserName.trim() -ne '')) {
9848+
# make sure we have a result
9849+
if (($UserName) -and ($UserName.trim() -ne '') -and (!($UserName -match $CurrentUser))) {
98719850

9872-
$TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object {
9851+
$TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object {
98739852

9874-
$Proceed = $True
9875-
if($DomainShortName) {
9876-
if ($DomainShortName.ToLower() -ne $UserDomain.ToLower()) {
9877-
$Proceed = $True
9878-
}
9879-
else {
9880-
$Proceed = $False
9881-
}
9882-
}
9883-
if($Proceed) {
98849853
$IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress
98859854
$FoundUser = New-Object PSObject
9886-
$FoundUser | Add-Member Noteproperty 'UserDomain' $UserDomain
9855+
$FoundUser | Add-Member Noteproperty 'UserDomain' $_.MemberDomain
98879856
$FoundUser | Add-Member Noteproperty 'UserName' $UserName
98889857
$FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName
98899858
$FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress
9890-
$FoundUser | Add-Member Noteproperty 'SessionFrom' $Null
9891-
$FoundUser | Add-Member Noteproperty 'SessionFromName' $Null
9859+
$FoundUser | Add-Member Noteproperty 'SessionFrom' $CName
9860+
9861+
# Try to resolve the DNS hostname of $Cname
9862+
try {
9863+
$CNameDNSName = [System.Net.Dns]::GetHostEntry($CName) | Select-Object -ExpandProperty HostName
9864+
$FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName
9865+
}
9866+
catch {
9867+
$FoundUser | Add-Member NoteProperty 'SessionFromName' $Null
9868+
}
98929869

98939870
# see if we're checking to see if we have local admin access on this machine
98949871
if ($CheckAccess) {
9895-
$Admin = Invoke-CheckLocalAdminAccess -ComputerName $ComputerName
9872+
$Admin = Invoke-CheckLocalAdminAccess -ComputerName $CName
98969873
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin
98979874
}
98989875
else {
@@ -9904,10 +9881,61 @@ function Invoke-UserHunter {
99049881
}
99059882
}
99069883
}
9907-
}
9884+
if(!$Stealth) {
9885+
# if we're not 'stealthy', enumerate loggedon users as well
9886+
$LoggedOn = Get-NetLoggedon -ComputerName $ComputerName
9887+
ForEach ($User in $LoggedOn) {
9888+
$UserName = $User.wkui1_username
9889+
# TODO: translate domain to authoratative name
9890+
# then match domain name ?
9891+
$UserDomain = $User.wkui1_logon_domain
9892+
9893+
# make sure wet have a result
9894+
if (($UserName) -and ($UserName.trim() -ne '')) {
9895+
9896+
$TargetUsers | Where-Object {$UserName -like $_.MemberName} | ForEach-Object {
9897+
9898+
$Proceed = $True
9899+
if($DomainShortName) {
9900+
if ($DomainShortName.ToLower() -ne $UserDomain.ToLower()) {
9901+
$Proceed = $True
9902+
}
9903+
else {
9904+
$Proceed = $False
9905+
}
9906+
}
9907+
if($Proceed) {
9908+
$IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress
9909+
$FoundUser = New-Object PSObject
9910+
$FoundUser | Add-Member Noteproperty 'UserDomain' $UserDomain
9911+
$FoundUser | Add-Member Noteproperty 'UserName' $UserName
9912+
$FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName
9913+
$FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress
9914+
$FoundUser | Add-Member Noteproperty 'SessionFrom' $Null
9915+
$FoundUser | Add-Member Noteproperty 'SessionFromName' $Null
9916+
9917+
# see if we're checking to see if we have local admin access on this machine
9918+
if ($CheckAccess) {
9919+
$Admin = Invoke-CheckLocalAdminAccess -ComputerName $ComputerName
9920+
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Admin.IsAdmin
9921+
}
9922+
else {
9923+
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null
9924+
}
9925+
$FoundUser.PSObject.TypeNames.Add('PowerView.UserSession')
9926+
$FoundUser
9927+
}
9928+
}
9929+
}
9930+
}
9931+
}
9932+
9933+
if ($Poll -gt 0) {
9934+
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
9935+
}
9936+
} While ($Poll -gt 0 -and $Timer.Elapsed.TotalSeconds -lt $Poll)
99089937
}
99099938
}
9910-
99119939
}
99129940

99139941
process {
@@ -9922,6 +9950,9 @@ function Invoke-UserHunter {
99229950
'CurrentUser' = $CurrentUser
99239951
'Stealth' = $Stealth
99249952
'DomainShortName' = $DomainShortName
9953+
'Poll' = $Poll
9954+
'Delay' = $Delay
9955+
'Jitter' = $Jitter
99259956
}
99269957

99279958
# kick off the threaded script block + arguments
@@ -9937,6 +9968,7 @@ function Invoke-UserHunter {
99379968

99389969
Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
99399970
$Counter = 0
9971+
$RandNo = New-Object System.Random
99409972

99419973
ForEach ($Computer in $ComputerName) {
99429974

@@ -9946,7 +9978,7 @@ function Invoke-UserHunter {
99469978
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
99479979

99489980
Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
9949-
$Result = Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName
9981+
$Result = Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $TargetUsers, $CurrentUser, $Stealth, $DomainShortName, 0, 0, 0
99509982
$Result
99519983

99529984
if($Result -and $StopOnSuccess) {

0 commit comments

Comments
 (0)