🔍COM Hijacking - T1546.015
Component object model hijacking method for persistence and privilege escalation.
0x01: Introduction
Adversaries may establish persistence by executing malicious content triggered by hijacked references to Component Object Model (COM) objects.
This technique is tagged as T1546.015 on MITRE ATT&CK and is a technique used by many threat actors for persistence and privilege escalation purposes, In this article I will in-depth on how the hijacking technique works and how to implement it and its many variants.
This technique can be performed by an ordinary, non-admin user and can achieve both persistence and privilege escalation, we'll discuss what makes it possible in the next section.
If you wish to read about COM objects with greater detail, read Demystifying Windows Component Object Model (COM)
COM Object Execution
Before we understand how to hijack a COM Object's execution, we need to know how it is executed.
Without diving into detail (for that you have Demystifying Windows Component Object Model (COM)), a COM object is implemented as either a DLL or an EXE. When a client program want to execute a COM object, it executes certain functions that initialize the steps for executing that COM Object.
One of those crucial steps is resolving the location of the COM Object's implementation in order to execute it, after it locates the implementation, if everything else went smoothly it executes it.
For the rest of the article I'll refer to an activated COM object as "COM Server".
COM Registry database
To locate a COM object, the registry is used. Windows Registry contains the mapping information for every COM object implementation on disk.
These are the locations of the registry keys from which you can extract the location of a COM Object:
HKEY_CLASSES_ROOT\CLSID
HKEY_CLASSES_ROOT\WOW6432Node\CLSID
There are additional locations, but for the sake of keeping this section short and clear, I'll discuss them in a later section to avoid confusion.
To retrieve the mapping (location) of the COM Object, we are required to use one of the following identifiers:
CLSID -
Class ID, Is a globally unique identifier (GUID) that Identifies a COM Class. CLSID -> {72C24DD5-D70A-438B-8A42-98424B88AFB8}
In GREEN, the full registry key path,
In BLUE, the CLSID of the COM Object,
In RED the location on disk of the COM Object's implementation which is a DLL implementation (.ocx is a DLL).
When executing a COM Object, the windows service manager (SCM) attempts to locate the CLSID it received as an argument in the registry, once it locates the key with the CLSID it queries its keys in attempt to find the COM server.
The keys that potentially contain the path to the COM Server are:
InprocServer32 - Path to a DLL Server
LocalServer32 - Path to an EXE Server
ProgID -
Program ID is A friendly name for a COM Class which can be used in a similar manner as CLSID.
The format of a ProgID is: <Program>.<Component>.<Version>, separated by periods and with no spaces, as in Wscript.Shell.1
When We instantiate a COM Object we can use ProgID instead of CLSID provided that the ProgID key in the registry contains the appropriate mapping to the relevant CLSID. As you can see ProgID acts like an alias to the actual CLSID of the COM Object.
In GREEN we see the full registry key path of the CLSID that this ProgID is mapped to
In BLUE, the name of the ProgID
In RED, the mapping CLSID that's mapped to this ProgID
The COM Object's server implementation location is always resolved via CLSID
The ProgID key contains and mapping to a CLSID which then contains the mapping to the actual DLL/EXE.
0x02: The Windows Registry
Registry Overview
COM Object execution hijacking can be achieved in a variety of methods; However, All of them* rely on a single registry principle which prioritize configuration inside certain hives over another.
Configurations on the HKEY_CURRENT_USER hive takes precedence over configurations inside the HKEY_LOCAL_MACHINE hive. The reason for that, is to enable a user-specific configuration (HKCU) whilst having a generic configuration as well (HLKM).
*The statement above is true when you decide to hijack without overwriting existing COM configuration in HKLM which is common practice when hijacking and also doesn't require administrative privileges
In case you don't know what the Registry is, In its simplest form, it's a database where you can store and retrieve configuration data.
A hive is a logical group of keys, subkeys, and values in the registry that has a set of supporting files loaded into memory when the operating system is started or a user logs in.
The Windows Registry has multiple hives, these hives are nested inside various KEYS, we'll only discuss the relevant keys that are required to understand the hijacking concept.
HKEY_CURRENT_USER (HKCU) - Contains settings that apply only to the interactive user.
The Interactive user can change keys and values that are nested inside this key, changing keys Does Not require administrative privileges under the current user hive.
HKEY_LOCAL_MACHINE (HKLM) - Contains default settings that can apply to all users on the local computer.
Only Administrator can Modify keys on this hive
HKEY_CLASSES_ROOT (HKCR) - Provides a view of the registry that merges the information from HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE
Unlike HKCU and HKLM that have an actual hive file on disk, this key does not. This is because HKCR is a combined view of the HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE hives.
32-bit application data and 64-bit application data in the Registry
On 64-bit windows systems, the configuration data of 32-bit application will be saved under different keys than the 64-bit application.
The structure of the keys will stay similar aside from being nested under the key Wow6432Node.
For example:
Key for 64-bit application will look like this:
HKEY_CURRENT_USER\SOFTWARE\Classes
Key for 32-bit application will look like this:
HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Classes
COM Identifiers & Registry
As we previously discussed, COM has two main types of identifiers it leverages to locate COM objects, CLSID and ProgID.
Below is an exhaustive list of location in which you can find these identifiers and query them, it is also where the SCM goes to look for the location of the COM Servers, note that under the keys with "CLSID" you'll find (surprise surprise) CLSIDs, and under the other ones you'll find ProgID.
Exhaustive list of COM Identifiers registry locations:
HKEY_CLASSES_ROOT
HKEY_CLASSES_ROOT\CLSID
HKEY_CLASSES_ROOT\WOW6432Node
HKEY_CLASSES_ROOT\WOW6432Node\CLSID
HKEY_CURRENT_USER\SOFTWARE\Classes
HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID
HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Classes
HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Classes\CLSID
HKEY_LOCAL_MACHINE\SOFTWARE\Classes
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID
0x03: Hijacking COM Objects - Examples
Many Threat Actors leverage COM Hijacking in their tooling for persistence purposes (APT28, Turla) and it is also available out-of-the-box in many offensive frameworks.
In this section i'll present and demonstrate multiple COM Hijacking techniques and their variants, some are well-known and some are less.
All of them has to do with hijacking the execution process of a COM object in one way or another. Further more, you can get creative by combining some of the techniques and features into some less known hijacking flows.
CLSID Hijacking
This is the most common form of hijacking. In which we modify the registry value InprocServer32 which contains the location of the target COM Server, and eventually map it to our own malicious COM Object.
For the hijack to succeed we need
A COM Object we compiled
Create/Edit the relevant registry Keys/Values of the to-be-hijacked COM Obejct
Explaining The Process
We Choose the target COM Object we wish to hijack. For example: Wscript.Shell COM Object, Its CLSID is - {72C24DD5-D70A-438B-8A42-98424B88AFB8}
These are the configuration of the selected target COM object as they appear in HKLM
3. If we check the same path for the HKCU hive, we see that nothing exists there (and it shouldn't usually), once we hijack this CLSID, this key will be created in this hive (HKCU)
Total Registry shows deleted keys which is why we still see the CLSID key in this image. This is residue from testing the technique previously, Normally the key itself wouldn't exist.
4.To create and edit the relevant registry keys i'll use the COMHijackToolKit which is a PowerShell script that's a part of acCOMplice.
In addition, I've compiled a COM Server (TestCOMServer.dll) using this source (COM Proxy will be explained later in this article) that we would use to replace the wshom.ocx server.
5. The script loads the COMHijackToolkit utility, Creates the registry value to point to our DLL in HKCU, then Executes the COM object (using a ProgID), then cleans up the registry by deleting the new registry values that hijack the object.
Let's execute the script init-com-hijack.ps1, We can see the script created the registry entry in HKCU that points to our DLL:
The result of executing our COM Server is a message box, we can also see that our dll was successfully loaded to the process that executed the COM object (powershell.exe).
PowerShell provides an easy wrapper for COM objects instantiation using a ProgID: New-Object -comObject <ProdID>
In our example I performed a cleanup of the registry key we created that hijacks the object, if we will not delete our key, every program that executes the WScript COM will execute our DLL instead.
Note that this hijack will only work for 64-bit, as we hijacked only the 64-bit version of this COM Object.
So processes such as Winword.exe that by default come as 32-bit will use the 32bit registry key to resolve the location of the DLL and most importantly will use a 32-bit implementation of the COM Object.
TreatAs Hijacking
This is another form of CLSID Hijacking, without modifying the actual server value(InprocServer32) in the registry. Instead, we specify the CLSID of a class that can emulate the current class.
Which means that we can use this key to redirect the execution of a certain COM object to a different one. This time only providing a different CLSID without modifying the InprocServer32 value of the original COM Object.
For the hijack to succeed we need
A COM Object we compiled
Register our COM object in the registry
Create/Edit the relevant registry Keys/Values of the to-be-hijacked COM Obejct
Explaining The Process
I'll use an example from Matt Nelson's and Casey Smith's lecture. As you can see we register a COM object of our own and then we add a TreatAs key to the COM Object we wish to hijack.
In this case we hijack the {3734FF83-6764-44B7-A1B9-55F56183CDB0} object and map it to points to our CLSID which is - {0000001-0000-0000-0000-0000FEEDACDC}
If we proceed to execute the original COM object by CLSID, we'll see that our .sct file is executed instead, opening calc.exe
The cool thing about this technique is that it evades simple detections that are based on detecting the modification of the InProcServer32 value in specific common COM Objects, and results only in editing the TreatAs value which is less common.
ProgID Hijacking
When a program instantiate a COM object with ProgID, it will go through a resolution process to determine the CLSID that's mapped to the ProgID.
For the hijack to succeed we need
A COM Object we compiled
Register our COM object in the registry
Create/Edit the relevant registry Keys/Values of the to-be-hijacked COM Obejct
Explaining The Process
We'll choose Wscript's COM whos CLSID is {72C24DD5-D70A-438B-8A42-98424B88AFB8} and identify its ProgID by navigating the to the CLSID key in the registry and observing the value of ProgID
You might have noticed the VersionIndependentProgID key, it provides an Independent name for the ProgID which enables programs to call it by its "common" name and not a version specific one.
2. Now that we know the ProgID we navigate to its location - \Classes\Wscript.Shell We can see that the ProgID is mapped to the {72C24DD5-D70A-438B-8A42-98424B88AFB8} CLSID which is indeed, the WScript COM Object's CLSID.
3. To Hijack the ProgID we are required to:
Create a new ProgID key in HKCU that is mapped to our desired COM Object CLSID
Register our own COM object (or use an existing one)
This screenshot below shows a .reg file that I'll use to import all registry changes with ease by using the command:
Let's Understand what's happening
Create a new ProgID I am creating a new registry key with the same name of the ProgID I want to hijack in HKCU and add a mapping to a Class ID (CLSID) I generated. This step causes the hijack to work and redirects every call made via this ProgID to the CLSID I mapped.
Registering our COM Object
Because I use a CLSID that I generated which didn't exist before, I am required to register it, otherwise the mapping will point nowhere and nothing will happen. So I am creating the CLSID key, along with the mapping to our DLL on disk and with the appropriate ProgID.
Registry state after the modification
Execution
As you can see, when executing WScript via ProgID we successfully hijack the execution
However, If we try to execute it via the CLSID which we DIDN'T hijack, the hijack will not work (as expected) and we will not see our message box. This technique variant can thwart detection mechanisms relying on modification of the InProcServer32 value in specific COM objects.
ScriptletURL - "Fileless" COM Execution
Instead of dropping to disk your custom COM object(DLL), you can utilize Windows Scripting Components (Scriptlets), the ScriptletURL configuration allows us to register a remote location containing an .sct file, that will be downloaded and executed. Windows Script Components provide you with an easy way to create Component Object Model (COM) components using scripting languages such as VBScript, JScript and JavaScript.
Script component technology is made up of the following:
The script component run-time (Scrobj.dll).
Interface handlers
Your script component file (a.sct file). In your script component, you specify which interface handler you want to use.
There are three main requirements to utilize the ScripletURL configuration
The script component run-time (Scrobj.dll) needs to be the "COM Server"
Create an appropriately structured .sct file
Provide a reachable address when specifying the location of the .sct file
I've taken this example from Matt Nelson (@enigma0x3) and Casey Smith (@subtee) lecture Windows Operating System Archaeology which I highly recommend watching, and used it to register a COM Object with the ScriptletURL option.
As you can see, we performed a ProgID hijack of the "Scripting.Dictionary" ProgID, in-addition to creating our CLSID with the relevant configuration to utilize the ScripletURL feature. The result is a registered COM Object, with the Windows Scripting Component Run-time (scrobj.dll) as it's server (InprocServer32) and a URL path that remotely retrieves the scriptlet from github.
When a program creates a new instance of the COM object we hijack using the ProgID Scripting.Dictionary it will fetch the .sct file from the URL, scrobj.dll will handle the registration details that exist within the file and will then invoke the relevant interfaces to execute the code inside (VBScript, Jscript, etc)
If you'd like to hijack an existing CLSID, you can enumerate the CLSID list in the registry and look for ones who uses ScriptletURL and modify that value.
0x04 Enhancing the Hijack
Choosing The Right COM Object
Identifying Common COM Objects
When you use COM Hijacking for persistence, you probably want the object you hijack to be executed relatively frequently and so you'd want COM objects that are actually getting called by the system or other programs.
One strategy you may take is opening your favorite monitoring tool such as Procmon, and monitor registry query event for any of the interesting keys we discussed(InprocServer32, TreatAs, ScriptletURL, CLSID, and any key under \Classes\), quantify the results and decide on an object to hijack.
Here's for example a Procmon session I monitored for 30 seconds, with the InProcServer32 filter inside the "Path" column yields 17K+ registry events (!). Of course you still need to filter and remove duplicates but this is enough to get you going :)
Missing Libraries
Another Interesting thing you can do is enumerate registered COM Object that points to non-existent DLLs by checking the InProcServer32 path and attempting to late the DLL on disk, and thus hijacking the execution without modifying the registry.
If you just want to quickly test that on your machine, acCOMplice has implemented a PowerShell function to do just that "Find-MissingLibraries"
Better Stability
Hijacking COM Objects can be risky business, modern Windows systems still use COM everywhere all the time, and you might brake the system if you hijack the wrong COM object with proper handling.
So you either have to "Choose The Right COM Object", or you can create your COM server as a Proxy DLL that will execute your code but also provide the program that called the original COM object with the actual implementation of the original COM object.
A PoC of this idea can be found here
This approach still doesn't guaranty 100% stability, however it does reduce the frequency of crashes and system breakage.
0x05 Conclusion
COM Hijacking is a common method for persistence and can appear in many forms and variations. Although COM is a complicated technology, detection of COM Hijacking is relatively easy when you know what to look for, which is mostly the modification of registry keys and values we discussed in this article. Consider also adding context and additional events to avoid false positives.
Although an old technology COM is still widely used by windows and worth getting to know.
If you're interested to learn COM in a more granular fashion I suggest to read Microsoft's Documentation or you can start with this page:Demystifying Windows Component Object Model (COM)
Last updated