CIMplant Part 1: Detection of a C# Implementation of WMImplant
Introduction
Windows Management Instrumentation (WMI) has been around for several years as a way to gather information from and manage remote or local computers. WMImplant written by @ChrisTruncer helps red teamers and penetration testers query remote systems for valuable information and issue commands much like how a C2 channel would operate. It does this by using PowerShell to issue commands against the local or a remote host to interact with the WMI database present on all Windows systems.
This database houses almost every type of information you can think of related to a computer: active users, hardware information, running services, all events that occur, etc. It's fairly easy to query this remote information and present it to the user. The challenge arises when attackers want to use WMI in a way that was unintended, such as a command and control channel or issuing system commands and obtaining the output. This is where WMImplant and it's newer associate CIMplant come into play.
CIMplant
Introducing CIMplant, a C# rewrite and expansion of WMImplant which uses either WMI or Common Information Model (CIM) (more accurately, Windows Management Infrastructure (MI)) to complete the same tasks as WMImplant, only in C#. I'll be using CIM and MI interchangeably in this post but just note that the two are related but different. Much like WMImplant, CIMplant uses the current user context or supplied credentials to connect to the local or remote host to complete a myriad of objectives. In that same vein, I wanted to keep aligned with WMImplant by:
- Only use WMI or MI for connections
- Allow use against systems with Device Guard in place
- Ensure users can easily determine the command syntax
Some ways I wanted to differ from WMImplant though are:
- Use CIM/MI as a main connection method (huge increase in speed)
- Limit PowerShell usage as much as I could
- Allow execution through Cobalt Strike's execute-assembly
Some example usage of the tool is below.
As much as I wanted to distance the tool from PowerShell completely, it wasn't possible without the help of a custom WMI Provider, which we'll go over in a future blog post and new version of the tool. For the rest of this post, I'll be touching on some detections for CIMplant in order to give defenders a head start on securing their network. I'm not a defender so my knowledge in this area is somewhat limited but I hope this serves as a primer on some things to look for. More information can be found from smarter people here or here.
Detections - WMI/CIM Connections
Of course, the first thing we'll want to be aware of is the initial WMI or CIM connection. In general, WMI uses DCOM as a communication protocol whereas CIM uses WSMan (or, WinRM). This can be modified for CIM, and is in CIMplant, but let's just go over the default values for now. For DCOM, the first thing we can do is look for initial TCP connections over port 135. The connecting and receiving systems will then decide on a new, very high port to use so that will vary drastically. For WSMan, the initial TCP connection is over port 5985. You can monitor both of these ports for remote connections but that may cause a lot of alerts if you have a larger network.
Next, let's go over some Windows events we can look for, starting with WMI. If you haven't already, you'll have to enable WMI Event Tracing. If you go into the WMI-Activity folder and select the Trace events, you'll want to look for Event ID 11. Now, you may get a ton of results since WMI events are quite noisy but if you can filter through the data for the "IsLocal" UserData property and look for false that would help. It might make more sense with the screenshot below of a remote connection from CIMplant.
In the above screenshot you can see that the client machine is not the local system, the NamespaceName supplied is the target system's IP address (should be "\.\root\cimv2") and the IsLocal parameter is false, all very clearly pointing to a remote connection. For comparison, below is a screenshot for a local WMI Event 11.
Now, I'll be the first to admit my PowerShell scripting is exceptionally rusty. But the following code will query all WMI events in the Trace log and filter on ID 11. It should get you all unique systems, users, and if the connection was local or not. (Please send me a more efficient and/or elegant way of obtaining this!)
$FilterHashTable = @{LogName = 'Microsoft-Windows-WMI-Activity/Trace';ID = 11}
$Events = Get-WinEvent -Oldest -FilterHashtable $FilterHashTable | ForEach-Object {
$Values = $_.Properties | ForEach-Object { $_.Value }
[PSCustomObject]@{
IsLocal = $Values[-1]
FQDN = $Values[5]
User = $Values[6]
}
}
$UniqueEvents = $Events | Group -Property "FQDN","User", "IsLocal" | select -Expand Name
$UniqueEvents
Next, let's look for any CIM/MI connections. The event you'll want to look for is in the log "Microsoft-Windows-WinRM/Analytic", or found under Applications and Services Logs -> Microsoft -> Windows -> Windows Remote Management in the Event Viewer. The ID of the event is 1295 with a category of User authentication. The screenshot below shows what the event looks like, and really isn't as informational as the WMI events above.
The PowerShell code above can easily be edited to pull values from this event log but I'll leave that up to the reader (just modify the LogName variable and mess with the output a bit). Unfortunately, I've looked through all of the logs in the Analytic, Debug, and Operational log files for WinRM and haven't found anything as useful as Event ID 1295. If you want to check out other log files, this is a good reference for places to look.
DebugFilePath Enumeration/Modification
One aspect of both WMImplant and CIMplant is that they make use of the DebugFilePath property within the Win32_OSRecoveryConfiguration class when direct info is unobtainable, such as in viewing file contents or downloading a file. This post goes over that in a bit more detail so I'll just touch on the event IDs for now.
Once again, we'll want to look for Event ID 11, only this one is a bit different than the previous ones we looked at. This one has the query to get all instances (there's only one) of the Win32_OSRecoveryConfiguration class. We can see the full query in the screenshot below.
To ensure both WMImplant and CIMplant do not interfere with the configuration of a system in a negative way, the DebugFilePath property within the Win32_OSRecoveryConfiguration class has to be pulled and saved for resetting back to normal. This is that initial instance pull event you see above. Next, CIMplant will edit the DebugFilePath property with various information. This will be shown in both Event ID 11 and Event ID 12 with basically the same information in each event message.
In the above screenshot, we can see a call to the PutInstance method which modifies the instance with the specified name. Since there's only one instance allowed for this class we don't really have to worry about the name at all. Once the modification is complete, CIMplant will pull that data and execute a command which changes depending on the desired function (ps, basic_info, etc.) and will then reset the DebugFilePath property to the original value. We'll go into more details on how this process is done in a later blog post.
This concludes the introduction of CIMplant and the primer on detections. As time goes by, we'll be releasing more posts diving into the details and the code of CIMplant, so if this interests you keep an eye out for that. I hope security professionals will find this tool useful and if you have any additions to the tool to make it more efficient or better I'd be happy to merge pull requests! As always, you can contact us via the FortyNorth website, Twitter, LinkedIn, or Facebook.