What is WMI?

WMI is Microsoft’s implementation of WBEM (Web Based Enterprise Management) which is based on CIM and allows for the remote management of multiple system components in Windows environments. WMI is used on a daily basis by sysadmins across large domains due to its flexibility and scalability. Easy to deploy, scripts that leverage WMI can be seen everywhere. Unfortunately, as with everything that is widely deployed, has “remote” capabilities and runs on “windows”: the dark force is strong around it (just for fun: MS17-010).

It is known that WMI can be abused in many ways to either gather information, make changes and create persistence mechanisms. An excellent article by Matt Graeber (@mattifestation) called Abusing Windows Management Instrumentation (WMI) to Build a Persistent, Asyncronous, and Fileless Backdoor was an eye opener for many of us in the cybersec world. We knew this was possible, but forgot how flexible it was. The main strength of WMI persistence is its stealthiness and effectiveness. When a command is executed by WMI as a result of “evil” the only thing you will see is WmiPrvse.exe as the process. Distinguishing a valid system action from an invalid one is very hard under these circumstances. In other words, WMI persistence defeats non-repudiation!

What I will cover here are different methods for detecting WMI persistence that you could leverage within your network to hunt for this treat.

Understanding WMI Persistence

First, rather than re-inventing the wheel, I will link here below the sources that I consulted to learn more about WMI:

WMI Persistence Template by Matt G.

We tweaked some of the parameters in the script to make sure the timer event launches every minute and that no cleanup is performed at the end. After launching it, we can inspect the newly created Event Consumers/Filters/Bindings as follows:

We can observe the BASE64 ciphered payload (hold on to this, as it will become one of our detection artifacts later).

Now let’s throw in that juicy iex keyword to the Splunk mix and see what it comes up with:
Query: WmiPrvse OR powershell AND "iex" (NOT *google* NOT splunk NOT TargetImage=*powershell* NOT TargetImage=*wmiprvse* NOT TargetImage=*chrome* NOT TargetImage=*vmware* NOT EventCode=600) | reverse | table _time, EventCode, Message

We start observing some other interesting events popping up here. Disregarding Sysmon EventCode 20 (belongs to the new 6.10 version) which will be dissected later, we can see 5861 (Source: Microsoft-Windows-WMI-Activity/Operational), 400 (Source: Windows Powershell / Message: Engine state is changed from None to Available)1 and 403 (Source: Windows Powershell / Message: Engine state is changed from Available to Stopped)2. All of them are standard Windows Events, I haven’t “enabled” anything in particular here. I’m just farming what the OS already gives you by default.

The interesting thing about all these events is that they all reveal the powershell code used as payload: powershell.exe -NoP -C iex ([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String((Get-ItemProperty -Path HKLM:\SOFTWARE\PayloadKey -Name PayloadValue).PayloadValue)))

Most interesting of them all is Event 5861, which is giving us a lot of information about the persistence, namely the Binding itself.

WMI Persistence via PowerLurk by Sw4mpf0x

We can reproduce the same Timer Triggered Event as above with more ease with this great script which allows for a lot of flexibility.

We can do many more things, but this post is mainly about how to detect such sneaky persistence mechanisms, so let’s go ahead and grab our majestic free install of Splunk Enterprise with a 60 day trial and let’s make use of our best friend Sysmon the Great.

WMI Persistence Detection

For the purposes of this test, I’ve used a “log all” approach with Sysmon, you can find a sample config file here(Threat Hunting Ecosystem as a Code is my next project, don’t look at it yet, it’s ugly!)

So let’s go ahead and create a new TimerEvent and see what our logs come up with. We shall use the following search:

LogName=Microsoft-Windows-WMI-Activity/Operational AND NOT EventCode=5858 AND NOT "sysmon"

First thing we notice is that Windows already comes with a default “WMI-Event Detector” which is Event Id 5860 in the Microsoft-Windows-WMI-Activity/Operational Log

TL;DR. Well it seems that the new capability added by Sysmon to monitor WMI Events (SYSMON EVENT ID 19 & 20 & 21 : WMI EVENT MONITORING [WmiEvent]) is nothing else but a few queries issued to the WMI service which are then reported back to their own log space (Sysmon/Operational). Essentially sysmon is registering itself here as a subscriber for intrinsic events. This pretty much means Sysmon is duplicating on effort here, since Windows already comes with native events to detect WMI operations. It doesn’t mean though that this feature is plain redundant, since our logging architecture could be simplified by just looking at Sysmon events rather than having to fork to Windows native events for WMI. Anyway, let’s keep digging shall we ;)

The only problem we noticed here is that, for Timer-based WMI Events, sysmon wasn’t generating any logs. So you need to monitor Windows Event Id 5859/5861 if you want to catch those.

And one other small but important piece of information is the presence of Event Id 5857 which is telling us who the provider is (an executable) whose task is to carry out the actions determined in the EventConsumer class:

Let’s commit that to memory for a second: %SystemRoot%\system32\wbem\scrcons.exe. What the event is telling us is the executable in charge of running our script. Riding the Google brave horses I was able to obtain good answers from the Internet Elders: https://msdn.microsoft.com/en-us/library/aa940177(v=winembedded.5).aspx Here it says that these are the handlers for common event consumers:

So essentially, even if you are NOT monitoring for either Sysmon Events 19, 20 & 21 or Windows native Events in the WMI/Operational space Ids 5857, 5859, 5860 & 5861, you can still detect the presence of potentially malicious WMI persistence by leveraging the event consumer handlers listed above. Let’s ask Sysmon for Scrcons.exe

Now what a surprise! you would be expeting that WmiPrvse.exe would start scrcons.exe, instead it’s this regular non-profit bloke svchost.exe. Sysmon is even providing us with the name Description: WMI Standard Event Consumer - scripting
Looking for further clues of scrcons.exe returns a Sysmon Event Id 11 (File Created) event where our little friend created a file.

If we were expecting to see this file, written to disk by wscript.exe we will be disappointed.

This time though, Sysmon seems to have noticed that a malicious event subscription was created and here we have it:

If you are using Sysmon events to monitor for WMI event subscriptions, you only need to capture the results of Event Id 19 as it will display the event consumer which is were the juicy information is that allows us to discriminate benign from malicious.

What happens if we instead create a CommandLine Event Subscription instead of a Script based one? The command would look like this with PowerLurk:

This time, instead of scrcons.exe we shall see wbemcons.dll as the event handler, and instead of a process being a child of another process we shall see WmiPrvse.exe loading wbemcons.dll . In all my experimental hunts I can assure you that the presence of wbemcons.dll being loaded as a module by WmiPrvse.exe is extremely rare, so do pay attention to those if you are not monitoring WMI/Operational native Windows events.

I will leave it as an exercise to the reader to investigate which events are generated by creating a CommandLine Event Consumer.

What about DFIR?

It happens to be the case that any permanent event subscription gets written to a WMI database file called OBJECTS.DATA that can be located here:

C:\Windows\System32\wbem\Repository\OBJECTS.DATA

C:\Windows\System32\wbem\Repository\FS\OBJECTS.DATA

It turns out that the information pertaining WMI event subscriptions can be located there in plain text. The file has a binary format and its structure, AFAIK, is undocumented. However, there are a few out there that were brave enough to come up with some cool python scripts that make use of The Sword of RegEx The Great and Meticulous that allow for parsing of these files, namely:

So even if you are (well… luckily after reading this post “were”) not collecting any WMI telemetry data in your environment, you can still go out there and hunt for these threats by collecting all the OBJECTS.DATA files in your hosts. The scripts listed above allow for easy parsing of a folder full of these files so the heavy lifting will be on the collecting side of things ;)

Detection Logics & Lessons Learned

You may think that WMI fileless persistence and malware execution mechanisms are a very low risk threat thus spending business cycles into creating a detection for this drops way down the list of priorities. It is, however, an extremely easy to detect tactic and if your priority list is not packed with threat scenarios like this one then you are not putting together a proper list! We all know looking at detailed TTPs is a tedious process, but only by adopting a systemic approach you will be able to extend your detection & prevention surface. It’s an ants work, mixed with that of a dragon.

Hopefully in my next post I will resume the Mimikatz one and then I will jump into Meterpreter detections ;)

Changes to your Sysmon Config

We will add a tag for the new event that has a pretty tight condition: it will only collect WMI events when they are created. This way, the FP ratio is reduced to a minimum, but as a trade off you need to be really paying attention and treat Alarms pertaining to these events as critical always.

Some references

List of modules involved in each WMI event https://msdn.microsoft.com/en-us/library/aa940177(v=winembedded.5).aspx

https://msdn.microsoft.com/en-us/library/aa392282(v=vs.85).aspx This explains how to create an NTEventLogEventConsumer class and how to setup one of its properties (insertionstrings) to a string. It also does this via MOF and compiling the MOF. The MOF then is embedded in OBJECTS.DATA. WMIPers is not parsing the “_EventConsumer” for these events very well, must look into that. The interesting thing though is that you could store anything in those “strings”, why not a payload?

https://msdn.microsoft.com/en-us/library/aa393016(v=vs.85).aspx Ability to register EventConsumers and EventFilters can be restricted by setting the EventAccess attribute of the EventFilter instance.