Dechaining via WMI
WMI is Microsoft's implementation of WBEM and CIM developed and published by DMTF. WMI provides means of gathering and sending management information in an enterprise environment.
WMI is a com based service which provides various variations of access to system related information.
WMI introduces something called a "managed object." This is a component on the machine that is managed by WMI. A managed object is a logical or physical part of a computer, such as a hard disk drive, network adapter, database system, operating system, process, or service. Applications that retrieve info from these managed objects are called "consumers."
Consumers query managed objects from these things called "providers." A provider is either a user-mode COM DLL or a kernel driver which expose . The default WMI providers are called the "standard providers", meaning that we can create our own provider and register it with WMI. This WMI provider is contains an associated GUID which is registered in the registry.
More specifically WMI providers provide information about managed objects as instances of classes, consumers do not access these instances directly, consumers query WMI, and WMI then forwards that query to the provider. The provider then processes the query and sends info back to WMI, in which WMI sends it back to the consumer again.

These queries happen in WQL, which is basically SQL for WMI. If you have programmed in SQL before, you will notice that the syntax is very similar.
An example of a WQL query is this:
This query will return all running processes where the executable names is chrome.
The diagram below shows the relationship of the WMI infrastructure and WMI providers and managed objects.

Examples of WMI providers are the Registry provider:
Which helps you access data in the registry. This provider only has one WMI class:
which is StdRegProv. This class has many methods which we can use.
WMI Providers also contain a Managed Object Format file which defines the classes which the provider returns.
Classes are also categorized hierarchically into namespaces. All namespaces derive from the ROOT namespace and Microsoft uses ROOT\CIMV2 as the default namespace.
WMI settings are stored here:
the WMI service is implemented as a service process within SVCHOST. This service interacts with consumers through the COM interface. Providers register their location with the WMI service, which allows WMI to route data requests.
WMI also uses ETW to record its own service activity.
For more information, please check out the Microsoft documentation:
For this lab(ish), we will just be using the standard providers to make any process of our choice spawn under wmiPRVSE.exe service.(in c/c++)
Implementation
Since we are dealing with COM, we must setup COM by calling CoInitializeEx. If you don't recall, COM is a a language agnostic library which allows application in different programming languages to interact with each other.
The steps to create a WMI application are to:
Initialize COM
Create a connection to a WMI namespace
Set security levels of the WMI connection
Use the COM interfaces(functionality)
cleanup and shutdown your application properly
Microsoft already has a code implementation on how to create a process using WMI, the final code is here(stolen from MS)
This part of the code includes the libraries to compile correctly:
We then call CoInitializeEx to setup COM
We then setup the COM security levels with CoInitializeSecurity. here, RPC_C_AUTHN_LEVEL_DEFAULT and RPC_C_IMPL_LEVEL_IMPERSONATE are the only parameters to be set.
after COM and COM-security have been set up, the class:IWbemLocator is used to access the WMI service, we initialize the IWebLocator interface through a call to CoCreateInstance.
IWbemLocator::ConnectServer connects to the specified host for WMI. Here, we will just use the local WMI service.
IWbemLocator::ConnectServer is defined with:
The first parameter specifies the CIM namespace the consumer connects to, like \\server\namespace... If the namespace is no the local machine, server can be omitted, like namespace\namespace1...
user and pass are in the second and third parameters, in the scenario if a local machine, they must be set to NULL or else they will fail
the fourth parameter if set to null, the current local will be used. If it is not NULL, this must be a valid BSTR
The fifth parameter if set to 0, results in ConnectServer returning only after the connection to the server is established, This could result in your program ceasing to respond indefinitely if the server is broken. The following list lists the other valid values for lSecurityFlags. Note that you can also set it to WBEM_FLAG_USE_MAX_WAIT, which guarantees the call to return within two minutes. This safeguards consumers against blocking indefinitely if the targeted machine is down
Our call looks like this:
Once you have received a pointer to the IWbemServices proxy, you will then have to set the security settings on the proxy to access WMI. Here, we call it so that impersonation of the client occurs on the proxy.
After that, we can finally access the Process::create method which will create a process under the WMI service.
We will use the IWbemServices pointer to make requests to WMI, we will use IWbemServices::ExecMethod to call Win32_Process::Create.
If the provider supports any in or out parameters, then the values of the parameters must be given to the IWbemClassObject pointers. For in parameters, you must spawn an instance of the in parameter definitions, and set the values of these new instances.
Process::Create needs a CommandLine in parameter to execute. As seen in its prototype:
Here, we will create a IWbemClassPointer, spawn a new instance of Win32_Process::Create, and set the value of CommandLine to notepad.exe.
We will then handle the out-parameters, giving it to an IWbemClassObject pointer. We will use the GET method and store it in a VARIANT variable so we can display it back to the user
We will then implement some error checking if anything fails, this simply prints out the error code and cleans and shuts down.
We release any open COM interfaces, free our allocated memory, call CoUninitialize, and exit our application:
Note that this is also what we do at the end of our code even if it works:
Observations
Let's compile the code above and see it in action!
We can see we spawned the WmiPrvSe service in Process Hacker like so:

And our notepad with WMiPrvSe.exe as its parent

We have successfuly spoofed notepad's parent to be the WMI service!
But there is a weird thing I found in which I don't have enough knowledge to explain why this happens.
After around one minute and thirty seconds, this popups up about notepad.exe

As we can see, it has a "Non-existent" parent.
ETW also has a WMI provider we can enable. We will use Event Viewer for this.
Lets enable tracing for the WMI-Activity, and see what kind of logs we get when we run our ppid spoofing executable:

Once enabled, lets run our executable.
...
If everything works, you should get a good amount of logs from one executable. I was too lazy to take screenshots of the logs, so I'll leave this as an "exercise" to the reader to test out.
TODO:
How can we detect this?
Does this trigger Image Load callbacks?
why does the WMI service quit after some time?
Last updated
Was this helpful?