@@ -9480,6 +9480,11 @@ function Invoke-UserHunter {
9480
9480
9481
9481
The maximum concurrent threads to execute.
9482
9482
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
+
9483
9488
. EXAMPLE
9484
9489
9485
9490
PS C:\> Invoke-UserHunter -CheckAccess
@@ -9534,6 +9539,13 @@ function Invoke-UserHunter {
9534
9539
Executes old Invoke-StealthUserHunter functionality, enumerating commonly
9535
9540
used servers and checking just sessions for each.
9536
9541
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
+
9537
9549
. LINK
9538
9550
http://blog.harmj0y.net
9539
9551
#>
@@ -9623,7 +9635,10 @@ function Invoke-UserHunter {
9623
9635
9624
9636
[Int ]
9625
9637
[ValidateRange (1 , 100 )]
9626
- $Threads
9638
+ $Threads ,
9639
+
9640
+ [UInt32 ]
9641
+ $Poll = 0
9627
9642
)
9628
9643
9629
9644
begin {
@@ -9632,9 +9647,6 @@ function Invoke-UserHunter {
9632
9647
$DebugPreference = ' Continue'
9633
9648
}
9634
9649
9635
- # random object for delay
9636
- $RandNo = New-Object System.Random
9637
-
9638
9650
Write-Verbose " [*] Running Invoke-UserHunter with delay of $Delay "
9639
9651
9640
9652
# ####################################################
@@ -9705,6 +9717,14 @@ function Invoke-UserHunter {
9705
9717
}
9706
9718
}
9707
9719
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
+
9708
9728
# ####################################################
9709
9729
#
9710
9730
# Now we build the user target set
@@ -9802,97 +9822,54 @@ function Invoke-UserHunter {
9802
9822
9803
9823
# script block that enumerates a server
9804
9824
$HostEnumBlock = {
9805
- param ($ComputerName , $Ping , $TargetUsers , $CurrentUser , $Stealth , $DomainShortName )
9825
+ param ($ComputerName , $Ping , $TargetUsers , $CurrentUser , $Stealth , $DomainShortName , $Poll , $Delay , $Jitter )
9806
9826
9807
9827
# optionally check if the server is up first
9808
9828
$Up = $True
9809
9829
if ($Ping ) {
9810
9830
$Up = Test-Connection - Count 1 - Quiet - ComputerName $ComputerName
9811
9831
}
9812
9832
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 (" \" )
9856
9846
}
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
9868
9847
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 ) )) {
9871
9850
9872
- $TargetUsers | Where-Object {$UserName -like $_.MemberName } | ForEach-Object {
9851
+ $TargetUsers | Where-Object {$UserName -like $_.MemberName } | ForEach-Object {
9873
9852
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 ) {
9884
9853
$IPAddress = @ (Get-IPAddress - ComputerName $ComputerName )[0 ].IPAddress
9885
9854
$FoundUser = New-Object PSObject
9886
- $FoundUser | Add-Member Noteproperty ' UserDomain' $UserDomain
9855
+ $FoundUser | Add-Member Noteproperty ' UserDomain' $_ .MemberDomain
9887
9856
$FoundUser | Add-Member Noteproperty ' UserName' $UserName
9888
9857
$FoundUser | Add-Member Noteproperty ' ComputerName' $ComputerName
9889
9858
$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
+ }
9892
9869
9893
9870
# see if we're checking to see if we have local admin access on this machine
9894
9871
if ($CheckAccess ) {
9895
- $Admin = Invoke-CheckLocalAdminAccess - ComputerName $ComputerName
9872
+ $Admin = Invoke-CheckLocalAdminAccess - ComputerName $CName
9896
9873
$FoundUser | Add-Member Noteproperty ' LocalAdmin' $Admin.IsAdmin
9897
9874
}
9898
9875
else {
@@ -9904,10 +9881,61 @@ function Invoke-UserHunter {
9904
9881
}
9905
9882
}
9906
9883
}
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 )
9908
9937
}
9909
9938
}
9910
-
9911
9939
}
9912
9940
9913
9941
process {
@@ -9922,6 +9950,9 @@ function Invoke-UserHunter {
9922
9950
' CurrentUser' = $CurrentUser
9923
9951
' Stealth' = $Stealth
9924
9952
' DomainShortName' = $DomainShortName
9953
+ ' Poll' = $Poll
9954
+ ' Delay' = $Delay
9955
+ ' Jitter' = $Jitter
9925
9956
}
9926
9957
9927
9958
# kick off the threaded script block + arguments
@@ -9937,6 +9968,7 @@ function Invoke-UserHunter {
9937
9968
9938
9969
Write-Verbose " [*] Total number of active hosts: $ ( $ComputerName.count ) "
9939
9970
$Counter = 0
9971
+ $RandNo = New-Object System.Random
9940
9972
9941
9973
ForEach ($Computer in $ComputerName ) {
9942
9974
@@ -9946,7 +9978,7 @@ function Invoke-UserHunter {
9946
9978
Start-Sleep - Seconds $RandNo.Next ((1 - $Jitter )* $Delay , (1 + $Jitter )* $Delay )
9947
9979
9948
9980
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
9950
9982
$Result
9951
9983
9952
9984
if ($Result -and $StopOnSuccess ) {
0 commit comments