- What is WMI?
- Understanding WMI Persistence
- How does a WMI persistent object look like?
- WMI Persistence Detection
- Detection Logics & Lessons Learned
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:
- Matt Graeber’s article (mentioned above)
- Pentestarmoury article “Creeping on Users with WMI Events” by Sw4mp_f0x. He also developed PowerLurk (see below)
- Permanent WMI Subscriptions
- Derbycon 2015 presentation by Matt
How does a WMI persistent object look like?
Let’s use two scripts that allow us to easily create a malicious persistence without having to do it step by step (have a look at the PS files to understand all the bits and pieces involved), namely:
- PowerLurk by Sw4mp_f0x
- WMI Persistence Template Gist by Matt G.
- Alternatively, you can also use an adaptation of Matt’s work by n0pe-sled WMI-Persistence.ps1
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:
As we can observe, this persistence is based off a Timer intrinsic Event type. If you launched it and head to C:\ you will see the payload_result.txt file as per the script:
Let’s look at the persistent registry key generated by the script via
Invoke-WmiMethod -Namespace root/default -Class StdRegProv -Name CreateKey -ArgumentList @($HiveVal, $PayloadKey) (creating the Registry Key) &
Invoke-WmiMethod -Namespace root/default -Class StdRegProv -Name SetStringValue -ArgumentList @($HiveVal, $PayloadKey, $EncodedPayload, $PayloadValue) (storing the payload value inside the key)
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.
this will simply start calc every 60 seconds and we can see the timer event
Let’s go ahead and remove it though:
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:
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
Second, becase I am running Powershell v5, Script Block Auditing is enabled by default, hence, the malicious script was also captured:
We also notice via another Event Id 5860 that some application with the Process Id 2024 issued a query to the WMI provider:
Who is this guy?
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.
What would happen if we create a script event consumer?
As we can observe, this pretty handy Windows Event Id 5861 provides all the information pertaining to the FilterToConsumerBinding, the EventConsumer and EventFilter
We also observe Windows Event Id 5859 showing the EventFilter which is effectively registered in the NotificationQueue:
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:
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:
- https://github.com/darkquasar/WMI_Persistence (developed by me)
- https://github.com/davidpany/WMI_Forensics (David Pany script)
- https://github.com/fireeye/flare-wmi (a few scripts by FireEye analysts)
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.
So, to summarize
|Sysmon Event Id 11 (File Write) where “Image” is “C:\WINDOWS\system32\wbem\scrcons.exe”.||Suspicious files written by the script event consumer handler||Environments with Sysmon monitoring|
|Sysmon Event Id 1 where “ParentImage” is C:\Windows\System32\svchost.exe AND Image is “C:\WINDOWS\system32\wbem\scrcons.exe”. Alternatively Windows Security Log Event ID 4688 (Process Created) can also be monitored.||Instances of an Active Script Event Consumer WMI Persistence||When you are not monitoring Windows native WMI/Operational events OR,when a malicious actor disabled native windows event logging and you have another technology in place (for example EDR)|
|Sysmon Event Id 7 where “Image” is C:\Windows\System32\wbem\WmiPrvSE.exe AND “ImageLoaded” contains “wbemcons.dll”.||Instances of an Active CommandLine Event Consumer Persistence||When you are not monitoring Windows native WMI/Operational events,OR,when a malicious actor disabled native windows event logging and you,have another technology in place (for example EDR)|
|Windows Event Id 5859 in WMI-Activity/Operational||Suspicious Event Consumers||Environments with no Sysmon monitoring using solely native Windows Events OR for Intrinsic Timer Events (Sysmon doesn’t catch those!)|
|Windows Event Id 5861 in WMI-Activity/Operational||Suspicious Event Filters||Environments with no Sysmon monitoring using solely native Windows Events OR for Intrinsic Timer Events (Sysmon doesn’t catch those!)|
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.
- Malware using WMI Persistence: WMIGhost / Actors: APT29POSHSPY
- Yeap, cryptominers WMI’ing the [email protected]# out of Browsers
- This dude man! mattifestation
- 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.
arrivederci my friends, wine and fettuccine awaits!