This is the third instalment of the “Offensive WMI” series (the 2nd is here), and this blog will focus on interacting with the Windows Registry. A useful thing to know before we start, MITRE ATT&CK classifies querying of registry values under T1012 and its modification under T1112.

Let’s dive in.

What is Windows Registry?

In simple terms, the registry is a database that stores configuration settings and options of the operating system: the kernel, device drivers, services, SAM, user interface and third party applications all make use of the registry. This makes the registry a very attractive resource for attackers.

The registry consists of sections known as hives, e.g. HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, etc. Upon inspection of the registry in regedit.exe, they appear to be arranged in a similar fashion to a filesystem. Each hive has a number of keys. The keys can have multiple subkeys. A key or subkey acts as a store for values. A registry item consists of a name and value pair.

Registry & WMI

WMI provides a class called StdRegProv for interacting with the Windows Registry. With this in hand, we can do a variety of things – including retrieval, creation, deletion and modification of keys and values. An important point to note here is that we need to use the root\DEFAULT namespace for working with the registry.

Let’s start by exploring what methods are available to us:

Get-WmiObject -Namespace root\default -Class StdRegProv -List | select -ExpandProperty methods
namespace

From the output above, we can see methods like CreateKey, DeleteKey, EnumKey, EnumValues, DeleteValues, etc, for interacting with the Registry. Interesting.

Two important things to know before jumping in:

  1. First, WMI uses constant numeric values to identify different hives in the registry. The table below lists the constants for accessing registry hives:

    Variable Value Hive
    $HKCR 2147483648 HKEY_CLASSES_ROOT
    $HKCU 2147483649 HKEY_CURRENT_USER
    $HKLM 2147483650 HKEY_LOCAL_MACHINE
    $HKUS 2147483651 HKEY_USERS
    $HKCC 2147483653 HKEY_CURRENT_CONFIG
  2. And secondly, the registry has different data types, and each data type can be accessed using a particular method in WMI. The table below maps common data types to their methods:

    Method Data Type Type Value Function
    GetStringValue REG_SZ 1 Returns a string.
    GetExpandedStringValue REG_EXPAND_SZ 2 Returns expanded references to env variables.
    GetBinaryValue REG_BINARY 3 Returns array of bytes.
    GetDWORDValue REG_DWORD 4 Returns a 32-bit number.
    GetMultiStringValue REG_MULTI_SZ 7 Returns multiple string values.
    GetQWORDValue REG_QWORD 11 Returns a 64-bit number.

Querying the registry

Enumerating keys

Now that we know the constants, let’s try to enumerate the available subkeys under a well-known registry path HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion. Putting together what we know so far, we can use this command to get all keys under the registry item:

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

NOTE: The same can be done with upper hierarchical registry paths as well. If you don’t know the absolute path, you can explore the registry by simply replacing the path in the command above.

e.g. – If you replace the path software\microsoft\windows nt\currentversion\schedule in the above command with just software, then the output will list all subkeys under the HKEY_LOCAL_MACHINE\Software. This is helpful when exploring unknown nested items in a registry.

Enumerating values

Now that we know how to list the keys available under the registry item, lets enumerate the values under the Drivers32 key:

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

As we can see, the output contains the subkey names under sNames and the associated data type under Types property. Of course, we can use Powershell’s select -ExpandProperty switch to have an extended view of the values of the properties returned in the output.

Reading values

Now let us try to read the values of the subkeys. For our example, we’ll be reading the values of the Drivers32 subkey (which defines the Windows NT DLLs for applications). Several malware variants have been observed making use of this key (see Riern Trojan Family) in the past.

The following command reads the value of the subkeys aux and midi under the Drivers32 key. Please note that the method name passed to the cmdlet (via the -Name switch) will vary depending upon the registry data type (see the datatype table above).

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

TIP: Here is a good cheatsheet of juicy locations in registry that can be useful for an attacker. You might want to try exploring them. :)

Modifying the registry

We now know about reading key and value pairs from the registry using WMI. These didn’t require administrative privileges so far, however – creation, deletion and updating the keys and values may require elevated privileges.

Let’s try to create new keys and subkeys. But before that, we need to check whether we have access to a specific registry item. Once again there are constants defining the access levels to the keys. The following table summarizes the permissions with associated constants:

Method Value Function
KEY_QUERY_VALUE 1 Query the values of a registry key
KEY_SET_VALUE 2 Create, delete, or set a registry value
KEY_CREATE_SUB_KEY 4 Create a subkey of a registry key
KEY_ENUMERATE_SUB_KEYS 8 Enumerate the subkeys of a registry key
KEY_NOTIFY 16 Change notifications for a registry key or for subkeys of a registry key
KEY_CREATE 32 Create a registry key
DELETE 65536 Delete a registry key
READ_CONTROL 131072 Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS and KEY_NOTIFY values
WRITE_DAC 262144 Modify the DACL in the object’s security descriptor
WRITE_OWNER 524288 Change the owner in the object’s security descriptor

Checking permissions of a key

For our example, we’ll pick the Run key under the hive HKEY_CURRENT_USER first, then the HKEY_LOCAL_MACHINE. Here’s how to do it:

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

The bGranted property in the output tells us whether we have access to the specific item in the registry. From the above example, we can clearly see that our user currently has access to the Run key under HKEY_CURRENT_USER but not HKEY_LOCAL_MACHINE.

Creating registry entries

Now that we know that we have write access to the registry key Run under HKEY_CURRENT_USER, we’ll add our favourite calculator app to the registry item. This will cause a calculator to pop up every time the system boots up, a very common technique seen in malwares to gain persistence.

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name SetStringValue @(2147483649, "software\microsoft\windows\currentversion\run", "C:\Windows\System32\calc.exe", "Calculator")
subkey

Boom, our calculator app has achieved persistence. :D

NOTE: An existing subkey under a registry key can also be updated using the same above.

Deleting registry entries

To delete a registry subkey we don’t need the value:

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

Creating new keys

In few cases, we might need to create keys under the main tree hierarchy. Let’s say we want to create a new key called CustomAgent under the HKEY_LOCAL_MACHINE\Software\OpenSSH registry item. The process looks extremely simple:

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CreateKey @(2147483650, "software\openssh\CustomAgent")
newkey

Deleting keys

Deleting the key is equally simple:

Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteKey @(2147483650, "software\openssh\CustomAgent")
newkey

Tools of the Trade

  • Registry.ps1 – has easy to use Powershell functions for enumerating, creating, deleting, updating keys, etc. Super useful when dealing with things manually.
  • Get-Information.ps1 – from Nishang gathers interesting information of a system via the registry.
  • Invoke-WmiCommand.ps1 – from Powersploit is a very useful script that helps in code execution via storing payloads in the registry using WMI as a pure C2 channel.
  • Invoke-SessionGopher.ps1 – from Powershell Empire hunts and decrypts RDP, WinSCP, FileZilla, PuTTY, etc, session informations from a system.

Conclusion

The registry is a treasure trove for attackers when it comes to gathering useful data. In addition, the registry can also be used to store payloads, serving as an ideal fileless attack vector and persistence mechanism. In a later part of the series, we’ll take a look at how to create our entire C2 infra using just WMI and the registry. Now that we are done with the basics, in our next blog we’ll start with basic reconnaissance with WMI.

That’s it for now friend. Cheerio! \o/