@@ -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