diff --git a/PowerShell/BloodHound.ps1 b/PowerShell/BloodHound.ps1 index 9f3dfff18..b7d800b8b 100644 --- a/PowerShell/BloodHound.ps1 +++ b/PowerShell/BloodHound.ps1 @@ -4851,6 +4851,81 @@ filter Get-NetSession { } +filter Get-LoggedOnLocal { +<# + .SYNOPSIS + + This function will query the HKU registry values to retrieve the local + logged on users SID and then attempt and reverse it. + Adapted technique from Sysinternal's PSLoggedOn script. Benefit over + using the NetWkstaUserEnum API (Get-NetLoggedon) of less user privileges + required (NetWkstaUserEnum requires remote admin access). + + Note: This function requires only domain user rights on the + machine you're enumerating, but remote registry must be enabled. + + Function: Get-LoggedOnLocal + Author: Matt Kelly, @BreakersAll + + .PARAMETER ComputerName + + The ComputerName to query for active sessions. + + .EXAMPLE + + PS C:\> Get-LoggedOnLocal + + Returns active sessions on the local host. + + .EXAMPLE + + PS C:\> Get-LoggedOnLocal -ComputerName sqlserver + + Returns active sessions on the 'sqlserver' host. + +#> + + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline=$True)] + [Alias('HostName')] + [Object[]] + [ValidateNotNullOrEmpty()] + $ComputerName = 'localhost' + ) + + # process multiple host object types from the pipeline + $ComputerName = Get-NameField -Object $ComputerName + + try { + # retrieve HKU remote registry values + $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', "$ComputerName") + + # sort out bogus sid's like _class + $Reg.GetSubKeyNames() | Where-Object { $_ -match 'S-1-5-21-[0-9]+-[0-9]+-[0-9]+-[0-9]+$' } | ForEach-Object { + $UserName = Convert-SidToName $_ + + $Parts = $UserName.Split('\') + $UserDomain = $Null + $UserName = $Parts[-1] + if ($Parts.Length -eq 2) { + $UserDomain = $Parts[0] + } + + $LocalLoggedOnUser = New-Object PSObject + $LocalLoggedOnUser | Add-Member Noteproperty 'ComputerName' "$ComputerName" + $LocalLoggedOnUser | Add-Member Noteproperty 'UserDomain' $UserDomain + $LocalLoggedOnUser | Add-Member Noteproperty 'UserName' $UserName + $LocalLoggedOnUser | Add-Member Noteproperty 'UserSID' $_ + $LocalLoggedOnUser + } + } + catch { + Write-Verbose "Error opening remote registry on '$ComputerName'" + } +} + + ######################################################## # # 'Meta'-functions start below @@ -6645,6 +6720,8 @@ function Get-BloodHoundData { # grab the users for the local admins on this server Get-NetLocalGroup -ComputerName $ComputerName -API | Where-Object {$_.IsDomain} + $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress + $Sessions = Get-NetSession -ComputerName $ComputerName ForEach ($Session in $Sessions) { $UserName = $Session.sesi10_username @@ -6657,9 +6734,8 @@ function Get-BloodHoundData { # make sure we have a result if (($UserName) -and ($UserName.trim() -ne '') -and ($UserName -notmatch '\$') -and (!($UserName -match $CurrentUser))) { - $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress $FoundUser = New-Object PSObject - $FoundUser | Add-Member Noteproperty 'UserDomain' $_.MemberDomain + $FoundUser | Add-Member Noteproperty 'UserDomain' $Null $FoundUser | Add-Member Noteproperty 'UserName' $UserName $FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName $FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress @@ -6688,7 +6764,6 @@ function Get-BloodHoundData { # TODO: better way to determine if network logon or not if($ComputerName -notmatch "^$UserDomain") { if (($UserName) -and ($UserName.trim() -ne '') -and ($UserName -notmatch '\$')) { - $IPAddress = @(Get-IPAddress -ComputerName $ComputerName)[0].IPAddress $FoundUser = New-Object PSObject $FoundUser | Add-Member Noteproperty 'UserDomain' $UserDomain $FoundUser | Add-Member Noteproperty 'UserName' $UserName @@ -6702,6 +6777,26 @@ function Get-BloodHoundData { } } } + + $LocalLoggedOn = Get-LoggedOnLocal -ComputerName $ComputerName + ForEach ($User in $LocalLoggedOn) { + $UserName = $User.UserName + $UserDomain = $User.UserDomain + + # ignore local account logons + if($ComputerName -notmatch "^$UserDomain") { + $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 + $FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null + $FoundUser.PSObject.TypeNames.Add('PowerView.UserSession') + $FoundUser + } + } } } }