mirror of
https://github.com/PowerShellMafia/PowerSploit
synced 2026-06-08 12:13:33 +00:00
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.
This commit is contained in:
+109
-77
@@ -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
|
||||
$Timer = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
$RandNo = New-Object System.Random
|
||||
|
||||
if($CName -and $CName.StartsWith("\\")) {
|
||||
$CName = $CName.TrimStart("\")
|
||||
}
|
||||
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
|
||||
|
||||
# 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
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user