Unmasking the Shadowy Side of WMI Part 1: Foundation

Tho Le
7 min readOct 23, 2023

Attackers are known for their innovative tactics, often harnessing legitimate tools and services to infiltrate, move laterally, and establish persistence within their target systems. One such tool that has found favor among cybercriminals is Windows Management Instrumentation (WMI).

Windows Management Instrumentation, or WMI, is a powerful management framework built into every Windows operating system. It was designed to provide system administrators with extensive control and insight into their Windows environments, allowing for remote administration, monitoring, and automation. However, like many tools developed for legitimate purposes, WMI can also be hijacked by malicious actors to wreak havoc under the radar.

This is a 2-part blog series on Windows Management Instrumentation (WMI) exploitation:

  • Part 1 — Foundation, we will establish a thorough understanding of WMI. we’ll delve into the inner workings of WMI, explaining its core functionalities, and how it has become an integral part of Windows system management. Understanding this foundational knowledge is crucial to grasp the extent of its manipulation by malicious actors in the next part of our series.
  • Part 2 — Exploitation, we will embark on a journey into the underbelly of WMI, exploring how attackers can skillfully manipulate it for reconnaissance, lateral movement, and persistence. As we delve into the world of stealthy exploitation, you’ll gain a deeper understanding of the techniques employed by these nefarious actors, empowering you with the knowledge needed to bolster your organization’s defenses and thwart their malicious intentions.

Introduction to WMI

Windows Management Instrumentation (WMI) is a fundamental component of Microsoft’s system management framework, serving as the Microsoft implementation of the Web-Based Enterprise Management (WBEM) standard. It plays a pivotal role in providing insights and control over systems, applications, networks, devices, and other managed components in the Windows ecosystem. WMI relies on the Common Information Model (CIM) industry standard to represent and manage these elements effectively. This standardized approach ensures consistency and interoperability, making WMI an indispensable tool for system administrators and IT professionals.

Applications and scripts can access WMI information and execute operations using WMI in a multitude of programming languages such as PowerShell, C/C++, .NET, VBScript, JSScript etc. One of the notable features of WMI is its ability to be accessed remotely, granting administrators the power to manage systems from a distance. This remote access is facilitated through two protocols: Distributed Component Object Model (DCOM) and Windows Remote Management (WinRM).

For those eager to explore this topic in greater detail, I recommend exploring the MS learning resources and referring to the excellent document by Matt Graeber.

WMI Architecture

WMI architecture and its components are presented in the figure below. In this session, we will explore each component with examples.

WMI Architecture (Source: https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture)

WMI Consumers (AKA management applications)
A WMI consumer is a management application or script that interacts with the WMI infrastructure to query, enumerate data, run provider methods, or subscribe to events.
A WMI consumer can be written in a variety of programming languages, namely .NET, VBScript, JScript, C/C++, Visual Basic, and PowerShell. There are also some GUI client tools to help the exploration of WMI easier, such as wbemtest.exe (built-in tool) and my togo tool wmiexplorer as in the screenshots below. If you are unfamiliar yet with terms in the GUIs (e.g. namespace, class, and instances), they will be explained later in the article.

Wbemtest.exe GUI interface
WMI GUI interface

WMI Query Language (WQL), which employs a syntax similar to SQL, is used to retrieve WMI Object data. Below are examples from wmiexplorer.exe and PowerShell

WQL example query via wmiexplorer.exe tool
WQL example query via PowerShell

WMI Infrastructure

WMI contains 2 main components: WMI Core and WMI Repository.
WMI repository is a central database used by WMI to store configuration and management data about a Windows system.
WMI Core (Winmgmt) acts as an intermediary between the providers, management applications, and the WMI repository. When a user issues a request from a management application, WMI core needs to know how the data of the requested object can be populated: (1) Only static data about objects is stored in the WMI repository, such as the classes defined by providers (2) most data are dynamically obtained from the provider upon request.

WMI Provider and Managed object
A managed object is either a logic or physical component such as a process, network adapter, or patch.

A WMI Provider is a COM server with a DLL and Managed Object Format (MOF) file (most of the time) to populate data about the object that it manages. A Provider defines WMI classes for which the provider returns data and performs operations. (Note: a provider may contain one or many classes). Let’s explore the details of the provider name and DLL to the class “Win32_Process” as in the PowerShell script below

$class = Get-CimClass -Class Win32_Process -Namespace 'root\cimv2'
$class_provider = $class.CimClassQualifiers["provider"].Value
# Get CLSID info
$class_provider_COM = Get-CimInstance -Class __Provider -Namespace 'root\cimv2' \
-Filter "Name='$($class_provider)'"|select Name, CLSID, CimClass
# Get COM DLL info
$DLL = (Get-ItemProperty -Path \
"HKLM:\Software\Classes\CLSID\$($class_provider_COM.CLSID)\InprocServer32")\
|Select-Object -ExpandProperty '(default)'
# display
write-host ("Class: $($class)")
write-host ("Provider: $($class_provider)")
write-host ("Provider's DLL: $($DLL)")

============================================================
============================================================
### Output
Class: ROOT/cimv2:Win32_Process
Provider: CIMWin32
Provider's DLL: C:\Windows\system32\wbem\cimwin32.dll

A WMI class is defined with properties and methods and is stored in a MOF file. Most MOF files can be found in “C:\Windows\System32\wbem” directory. As can be seen from the figure below, the properties and methods of the Win32_Process class are clearly defined.

Win32_Process class from cimwin32.mof file

Alternatively, it is also possible to explore class properties and methods via scripts. The PowerShell script below shows the properties and methods of the class “Win32_Process”

# Get all properties of Win32_Process
(Get-CimClass -ClassName Win32_Process).CimClassProperties|format-table


Name Value CimType Flags Qualifiers ReferenceClassName
---- ----- ------- ----- ---------- ------------------
Caption String Property, ReadOnly, NullValue {MaxLen, read}
Description String Property, ReadOnly, NullValue {read}
InstallDate DateTime Property, ReadOnly, NullValue {MappingStrings, read}
Name String Property, ReadOnly, NullValue {read}
Status String Property, ReadOnly, NullValue {MaxLen, read, ValueMap}
...truncated...
CommandLine String Property, ReadOnly, NullValue {read}
ExecutablePath String Property, ReadOnly, NullValue {MappingStrings, Privileges, read}
...truncated...

# Get all methods of Win32_Process
(Get-CimClass -ClassName Win32_Process).CimClassMethods

Name ReturnType Parameters Qualifiers
---- ---------- ---------- ----------
Create UInt32 {CommandLine, CurrentDirectory, ProcessStartupInformation, ProcessId} {Constructor, Implemented, MappingStrings, Privileges...}
Terminate UInt32 {Reason} {Destructor, Implemented, MappingStrings, Privileges...}
GetOwner UInt32 {Domain, User} {Implemented, MappingStrings, ValueMap}
GetOwnerSid UInt32 {Sid} {Implemented, MappingStrings, ValueMap}
SetPriority UInt32 {Priority} {Implemented, MappingStrings, ValueMap}
AttachDebugger UInt32 {} {Implemented, ValueMap}
GetAvailableVirtualSize UInt32 {AvailableVirtualSize}

# Get details of parameters of a method
(Get-CimClass -ClassName Win32_Process).CimClassMethods['Create'].Parameters

Name CimType Qualifiers ReferenceClassName
---- ------- ---------- ------------------
CommandLine String {ID, In, MappingStrings}
CurrentDirectory String {ID, In, MappingStrings}
ProcessStartupInformation Instance {EmbeddedInstance, ID, In, MappingStrings}
ProcessId UInt32 {ID, MappingStrings, Out}

# with parameter info, invoke "create" to spawn a new process (PID 5708 - notepad.exe)
Invoke-CimMethod -ClassName Win32_Process -MethodName "Create" -Arguments @{
CommandLine = 'notepad.exe'; CurrentDirectory = "C:\windows\system32"
}

ProcessId ReturnValue PSComputerName
--------- ----------- --------------
5708 0

A WMI instance is an object of a WMI class. Similar to Object-oriented programming, a WMI class can have 0 or many instances. In the example below, each running process in my test machine is an instance of Win32_Process.

Get-CimInstance -ClassName Win32_Process

ProcessId Name HandleCount WorkingSetSize VirtualSize
--------- ---- ----------- -------------- -----------
0 System Idle Process 0 8192 8192
4 System 2419 20480 3985408
108 Registry 0 12701696 155979776
368 smss.exe 53 245760 2203359711232
476 csrss.exe 496 2367488 2203412324352
552 wininit.exe 162 1437696 2203387641856
568 csrss.exe 441 2519040 2203436158976
652 winlogon.exe 274 2904064 2203420504064

Alternatively, all information about classes, methods, properties and instances can be easily explored via the neat visualization of WMIexplorer.exe tool.

Info of “Win32_Process” class and instances

Namespace is a hierarchy starting from root to organize classes as seen in the figure below

WMI Namespace hierarchy

Create Your Own WMI Class

In addition to the ‘built-in’ WMI providers and classes, it’s possible to create custom providers and classes. Among these, the creation of custom classes holds particular significance, as it has been exploited by malicious actors for covert purposes. Adversaries have leveraged custom classes to (1) secretly store data (e.g. fileless malware) and (2) execute lateral movement to other systems, highlighting the potential risks associated with this WMI capability. Further exploration of this topic will take place in the upcoming second part of this series.

The PowerShell script below illustrates the creation of a new class, namely “Win32_Malware” in “Root\cimv2” namespace. The class simply contains one property “payload” to store unlimited string data (e.g. malware configuration, actual malware payload, output from an execution, etc.)

# Create a new class
$newClass = New-Object System.Management.ManagementClass("root\cimv2",[string]::Empty,$null)
$newClass["__CLASS"] = "Win32_Malware"
$newClass.Qualifiers.Add("Static",$true)
$newClass.Properties.Add("Payload","This is fileless malware payload, execute upon retrieve")
$newClass.Put()
===> output
Path : \\.\root\cimv2:Win32_Malware
RelativePath : Win32_Malware
Server : .
NamespacePath : root\cimv2
ClassName : Win32_Malware
IsClass : True
IsInstance : False

# Data retrieval
(Get-CimClass -Class Win32_Malware -Namespace 'root\cimv2').CimClassProperties|Select-Object Name,Value
===> output
Name Value
---- -----
Payload This is fileless malware payload, execute upon retrieve

--

--

Tho Le

Senior Cyber Security Analyst — be better than the yesterday self