Living Off The Land - Built-In Pwning
Living off the land in the context of cybersecurity involves using existing tools, utilities, or scripts found on a target system. This post will dive into some of the useful built-in modules.
Common examples of these tools include CMD, PowerShell, WMI, and other built-in administrative tools that can be leveraged to enumerate and exploit vulnerabilities across a system or domain.
Adversaries can use this approach to help avoid detection by security solutions such as anti-virus (AV) and endpoint detection and response (EDR), which typically focus on detecting more obvious threats. By using existing and legitimate tools, adversaries can attempt to blend in with regular user activity and evade detection.
The phrase 'PowerShell is dead' has been coined for years, but even with protections enabled, it is still very much alive in many environments. PowerShell is a robust command-line shell and scripting language that can interact with Windows Management Instrumentation(WMI) on Windows-based computers and other modules. PowerShell provides several cmdlets and modules that enable administrators to query WMI, retrieve information, and perform various management tasks.
The following lab was created to demonstrate some easy techniques for quick enumeration wins:
Domain - hacklab.local
Domain Controller - Microsoft Windows Server 2022 10.0.20348 N/A Build 20348
Domain Host 1 - Microsoft Windows 11 Enterprise 10.0.22621 N/A Build 22621
Domain Host 2 - Microsoft Windows 11 Enterprise 10.0.22621 N/A Build 22621
Get-CimInstance
Get-CimInstance
is a PowerShell cmdlet which was introduced in Windows PowerShell version 3.0. It can be used to retrieve information about a host or domain. Still, more specifically, it allows you to retrieve information about one or more instances of a particular class from a CIM (Common Information Model) repository.
In other words, Get-CimInstance
enables you to query a system's CIM repository to retrieve a wide range of system information, including hardware configurations, installed software, and network settings. It is similar to the older Get-WmiObject cmdlet but uses, the newer CIM infrastructure instead of WMI.
Combining the Get-CimInstance with a Windows Management Instrumentation (WMI) class such as Win32_GroupInDomain
, can be used to retrieve detailed information such as all domain groups or a specific group that is a member of a domain. This can be useful when enumerating users' access and permissions across a Windows domain.
Domain Group Enumeration
PS C:\Users\user1> Get-CimInstance -ClassName Win32_GroupInDomain | Where-Object {$_.GroupComponent -match "Win32_NTDomain"} | Format-Table PartComponent -AutoSize
PartComponent
-------------
Win32_Group (Name = "Cert Publishers", Domain = "HACKLAB")
Win32_Group (Name = "RAS and IAS Servers", Domain = "HACKLAB")
Win32_Group (Name = "Allowed RODC Password Replication Group..., Domain = "HACKLAB")
Win32_Group (Name = "Denied RODC Password Replication Group", Domain = "HACKLAB")
Win32_Group (Name = "DnsAdmins", Domain = "HACKLAB")
Win32_Group (Name = "accounts", Domain = "HACKLAB")
Win32_Group (Name = "administration", Domain = "HACKLAB")
Win32_Group (Name = "Cloneable Domain Controllers", Domain = "HACKLAB")
Win32_Group (Name = "DnsUpdateProxy", Domain = "HACKLAB")
Win32_Group (Name = "Domain Admins", Domain = "HACKLAB")
Win32_Group (Name = "Domain Computers", Domain = "HACKLAB")
Win32_Group (Name = "Domain Controllers", Domain = "HACKLAB")
Win32_Group (Name = "Domain Guests", Domain = "HACKLAB")
Win32_Group (Name = "Domain Users", Domain = "HACKLAB")
Win32_Group (Name = "Enterprise Admins", Domain = "HACKLAB")
Win32_Group (Name = "Enterprise Key Admins", Domain = "HACKLAB")
Win32_Group (Name = "Enterprise Read-only Domain Controllers..., Domain = "HACKLAB")
Win32_Group (Name = "Group Policy Creator Owners", Domain = "HACKLAB")
Win32_Group (Name = "help_desk", Domain = "HACKLAB")
Win32_Group (Name = "Key Admins", Domain = "HACKLAB")
Win32_Group (Name = "Protected Users", Domain = "HACKLAB")
Win32_Group (Name = "RDP", Domain = "HACKLAB")
Win32_Group (Name = "Read-only Domain Controllers", Domain = "HACKLAB")
Win32_Group (Name = "sales", Domain = "HACKLAB")
Win32_Group (Name = "Schema Admins", Domain = "HACKLAB")
Win32_Group (Name = "support", Domain = "HACKLAB")
Domain User Account Enumeration
PS C:\Users\user1> Get-CimInstance -ClassName Win32_UserAccount | Format-Table -AutoSize
Name Caption AccountType SID Domain
---- ------- ----------- --- ------
admin DESKTOP-UH58RJD\admin 512 S-1-5-21-24335520-1574975053-1288484576-1001 DESKTOP-UH58RJD
Administrator DESKTOP-UH58RJD\Administrator 512 S-1-5-21-24335520-1574975053-1288484576-500 DESKTOP-UH58RJD
DefaultAccount DESKTOP-UH58RJD\DefaultAccount 512 S-1-5-21-24335520-1574975053-1288484576-503 DESKTOP-UH58RJD
Guest DESKTOP-UH58RJD\Guest 512 S-1-5-21-24335520-1574975053-1288484576-501 DESKTOP-UH58RJD
WDAGUtilityAccount DESKTOP-UH58RJD\WDAGUtilityAccount 512 S-1-5-21-24335520-1574975053-1288484576-504 DESKTOP-UH58RJD
Administrator HACKLAB\Administrator 512 S-1-5-21-2638285952-2988835435-2893458979-500 HACKLAB
Guest HACKLAB\Guest 512 S-1-5-21-2638285952-2988835435-2893458979-501 HACKLAB
krbtgt HACKLAB\krbtgt 512 S-1-5-21-2638285952-2988835435-2893458979-502 HACKLAB
n.collins HACKLAB\n.collins 512 S-1-5-21-2638285952-2988835435-2893458979-1109 HACKLAB
o.davidson HACKLAB\o.davidson 512 S-1-5-21-2638285952-2988835435-2893458979-1110 HACKLAB
p.davies HACKLAB\p.davies 512 S-1-5-21-2638285952-2988835435-2893458979-1111 HACKLAB
q.dawson HACKLAB\q.dawson 512 S-1-5-21-2638285952-2988835435-2893458979-1112 HACKLAB
u.dixon HACKLAB\u.dixon 512 S-1-5-21-2638285952-2988835435-2893458979-1113 HACKLAB
r.edwards HACKLAB\r.edwards 512 S-1-5-21-2638285952-2988835435-2893458979-1114 HACKLAB
s.elliot HACKLAB\s.elliot 512 S-1-5-21-2638285952-2988835435-2893458979-1115 HACKLAB
t.evans HACKLAB\t.evans 512 S-1-5-21-2638285952-2988835435-2893458979-1116 HACKLAB
u.fisher HACKLAB\u.fisher 512 S-1-5-21-2638285952-2988835435-2893458979-1117 HACKLAB
v.fletcher HACKLAB\v.fletcher 512 S-1-5-21-2638285952-2988835435-2893458979-1118 HACKLAB
w.ford HACKLAB\w.ford 512 S-1-5-21-2638285952-2988835435-2893458979-1119 HACKLAB
x.foster HACKLAB\x.foster 512 S-1-5-21-2638285952-2988835435-2893458979-1120 HACKLAB
y.fox HACKLAB\y.fox 512 S-1-5-21-2638285952-2988835435-2893458979-1121 HACKLAB
z.gibson HACKLAB\z.gibson 512 S-1-5-21-2638285952-2988835435-2893458979-1122 HACKLAB
a.graham HACKLAB\a.graham 512 S-1-5-21-2638285952-2988835435-2893458979-1123 HACKLAB
b.grant HACKLAB\b.grant 512 S-1-5-21-2638285952-2988835435-2893458979-1124 HACKLAB
c.gray HACKLAB\c.gray 512 S-1-5-21-2638285952-2988835435-2893458979-1125 HACKLAB
d.green HACKLAB\d.green 512 S-1-5-21-2638285952-2988835435-2893458979-1126 HACKLAB
m.jenkins HACKLAB\m.jenkins 512 S-1-5-21-2638285952-2988835435-2893458979-1127 HACKLAB
n.johnson HACKLAB\n.johnson 512 S-1-5-21-2638285952-2988835435-2893458979-1128 HACKLAB
A more exciting demonstration consists of using Get-CimInstance along with Win32_UserAccount to retrieve information about user accounts on the system combined with a Where-Object:
{ -not [string]::IsNullOrEmpty($_.Description) }
This filters the output to include only instances where the description property is not null and not an empty string. In other words, only reveal domain accounts with a description attribute filled out; people sometimes put interesting notes or passwords in the description attribute.
PS C:\Users\user1> Get-CimInstance -ClassName Win32_UserAccount | Where-Object { -not [string]::IsNullOrEmpty($_.Description) } | Select-Object -Property Name, Description, Domain, SID
Name Description Domain SID
---- ----------- ------ ---
Administrator Built-in account for administering the computer/domain DESKTOP-UH58RJD S-1-5-21-24335520-1574975053-1288484576-500
DefaultAccount A user account managed by the system. DESKTOP-UH58RJD S-1-5-21-24335520-1574975053-1288484576-503
Guest Built-in account for guest access to the computer/domain DESKTOP-UH58RJD S-1-5-21-24335520-1574975053-1288484576-501
WDAGUtilityAccount A user account managed and used by the system for Windows Defender Application Guard scenarios. DESKTOP-UH58RJD S-1-5-21-24335520-1574975053-1288484576-504
Administrator Built-in account for administering the computer/domain HACKLAB S-1-5-21-2638285952-2988835435-2893458979-500
Guest Built-in account for guest access to the computer/domain HACKLAB S-1-5-21-2638285952-2988835435-2893458979-501
krbtgt Key Distribution Center Service Account HACKLAB S-1-5-21-2638285952-2988835435-2893458979-502
d.atkinson User Password Summer123 HACKLAB S-1-5-21-2638285952-2988835435-2893458979-1179
Another great tool that we use a lot at Lares is ADSI Searcher. ADSI (Active Directory Service Interfaces) Searcher is a programming interface used to search for and retrieve information from Active Directory, a directory service developed by Microsoft for Windows domain networks.
The ADSI Searcher provides a means to programmatically access and manipulate Active Directory objects, including user accounts, groups, organizational units, and other directory objects. It allows developers to perform searches based on criteria such as object type, attribute values, and other conditions.
The ADSI Searcher is often used in automation and scripting scenarios, such as automated user provisioning, account management, and other administrative tasks. It provides a powerful way to manage and automate large-scale Active Directory environments and thus a great avenue for attackers to live off the land.
Find where WinRM is enabled on all domain hosts.
([adsisearcher]"(&(objectCategory=computer)(objectClass=computer))").FindAll() | ForEach-Object {Test-NetConnection -ComputerName $_.Properties.name -Port 5985 -ErrorAction SilentlyContinue | Where-Object {$_.TcpTestSucceeded -eq $true} | Select-Object ComputerName}
Example output:
PS C:\Windows\system32> ([adsisearcher]"(&(objectCategory=computer)(objectClass=computer))").FindAll() | ForEach-Object {Test-NetConnection -ComputerName $_.Properties.name -Port 5985 -ErrorAction SilentlyContinue | Where-Object {$_.TcpTestSucceeded -eq $true} | Select-Object ComputerName}
WARNING: TCP connect to (fe80::5615:5a87:8d00:a170%5 : 5985) failed
WARNING: TCP connect to (192.168.68.113 : 5985) failed
ComputerName
------------
WIN-CH4HJ7UU7Q5
LAB_WIN11_1
The query above can be used for any port to perform password spraying too. The following queries are additional queries that can be used for enumeration that do not require additional installs or modules.
Query all Computers and Search for Local admin.
$searcher=[adsisearcher]'objectCategory=computer'; $searcher.PageSize = 1000; $computer_list = $searcher.FindAll() | ForEach-Object{$_.Properties.name}; foreach ($computer in $computer_list) { try { $path = "\\" + $computer + "\C$\"; if(Test-Path $path -ErrorAction SilentlyContinue) { $string = "[!] Local Admin to: " + $computer; Write-Host $string }} catch {}}
$computers = @((New-Object DirectoryServices.DirectorySearcher("(&(objectCategory=computer)(operatingSystem=Windows*))")).FindAll() | ForEach-Object { $_.Properties.name[0] })
$username = Read-Host -Prompt "Enter your username"
$password = Read-Host -Prompt "Enter your password" -AsSecureString
$credential = New-Object System.Management.Automation.PSCredential ($username, $password)
$computers | ForEach-Object {
$computer = $_
$scriptBlock = {
Try {
$smb = Get-SmbSession
Write-Host "SMB service is accessible on $($env:COMPUTERNAME)" -ForegroundColor Green
} Catch {
$error_message = $_.Exception.Message
if ($error_message -notlike "*The user name or password is incorrect.*") {
Write-Host $error_message -ForegroundColor Red
}
}
}
Invoke-Command -ComputerName $computer -Credential $credential -ScriptBlock $scriptBlock -ErrorAction SilentlyContinue
}
Pull only active computers (lastlogon<31) (No test connection, with time throttle function (can be 0 for no time throttle))
$sleep_secs=0; $date_offset=-31; $searcher=[adsisearcher]"(&(objectCategory=computer)(lastlogon>=$((Get-Date).AddDays($date_offset).ToUniversalTime().ToFileTime())))";$searcher.PageSize = 1000; $computer_list = $searcher.FindAll() | ForEach-Object{$_.Properties.name}; $start_date=Get-Date; $info_source="`nCurrent Time: " + $start_date + "`nActive Workstations: " + $computer_list.count + "`nThrottle Seconds: " + $sleep_secs; Write-Host $info_source `n; foreach ($computer in $computer_list) { try { Start-Sleep -Seconds $sleep_secs; $path = "\\" + $computer + "\C$\"; if(Test-Path $path -ErrorAction SilentlyContinue) { $string = "`t[!] Admin to: " + $computer; Write-Host $string }} catch {}} $end_time=Get-Date; Write-Host "`nFinished! - " $end_time`n;
Thanks for reading this quick overview of living off the land; many modules can be used in Powershell with built-in tooling; if you want more examples, my colleague Andy and I have released more research here https://github.com/myexploit/living_off_the_land.