Extra Credits I: COM Objects Attacking & Detecting

Happy new year!

Outside of the bread and butter of the DFIR of Windows, I haven't over explored what I'd deem more niche or old but tried and tested concepts that I believe are sometimes overlooked, so I've set out to research, test and share some findings; with this being the first. This is in no means an attempt to deep-dive, but enough for a logical understanding to explore further, or hopefully help detect and respond to exploitation of such features/protocols. 

If you have any comments/additions or disagreements, I'm very open to discussion and to learn.


Windows Component Object Model (COM) 

If you are not interested in reading a summary on what COM actually is, or how it works skip to section "The "Offensive" Approach (How Hackers abuse COM Objects)" where an initial summary of attacks, followed by a demo and some topics on detection and response can be seen.

Windows Component Object Model (COM) in a simple term is a plug and play utility provided by Windows wherein software can communicate through a set of rules defined by COM both locally and remotely, regardless of which programming language they were written in. Despite its age, COM remains a fundamental pillar of the Windows subsystem, facilitating inter-process communication for core OS components.

First off it's good to know that:

A COM component is registered in the Windows Registry with a CLSID (Class ID), which the COM runtime uses to locate and activate the server. An IID (Interface ID) identifies an interface contract whose methods are implemented by the component and exposed via a vtable.

These rules entail utilising 3 key identifiers:

1. CLSID: (Class ID) which is a unique identifier for a software tool, which is used for identification.
2. IID: (Interface ID) identification of the features 
3. vtable: (Virtual Function Table) the IID points to a vtable (essentially a memory map of function addresses), as such the specific code/logic can be executed.

Within the Registry itself (using In-Proc as an example), you will find

1. CLSID Key
2. Subkey (InProcServer32, used for In-Proc) (May be LocalServer32, AppId, InprocHandler32..)
3. Data containing the path to the software 'tool' (DLL/Exe, etc)

Take this example within my system.


Example of a CLSID entry using In-Proc type

TLDR; by developers following a set of rules, it allows functionality (components) from other software to be shared, through the use of COM. Think of Word sharing features with Excel and vice versa.

Some examples may include:

- Embedding an Excel chart within word (utilising aa part of COM called OLE (Object Linking & Embedding)

- Drag and Drop: Ability to drag a file from one folder to another or into an application

- DirectX & Multimedia: Many high-performance graphics and sound systems are built on COM interfaces to ensure different hardware can talk to the same software.

So why do we care? Well, hackers do!

Windows COM has been around for a very long time, it is quite trivial to perform but looks very different to common TTPs observed in majority of intrusions; as such I believe it has the capability to fly under the radar or in some cases be responded to with "this is normal system behaviour".

T1546.015 T1559.001

COM Server Types/Models

There are many COM Server Types, these essentially define and adjust the activation, security and procedures, but in nature can be aggregated (for the sake of doom scrolling).


Although not an exhaustive list, but these are the 3 primary types.

Server Types / Examples


Last of the waffling before we practical analysis

To visualize this, I’ve mapped out a high level COM activation flow below. While this abstracts away some of the deeper RPC plumbing (as well as some additional inner workingns, it highlights the critical handshakes between the Registry, the Runtime, and the Object itself.

High-level overview
The following can be used in reference to the flow above.

1. How does it know?? 3 ways!
  • Hard-coded CLSIDs: Developers embed the exact 128-bit GUID into their code. Thus on a call, this information is already available.
  • Programmatic IDs (ProgID): The app uses a human-friendly nickname (such as Excel.Application). The COM Runtime looks this up in the registry to find the corresponding CLSID.
  • Enumeration: The app asks for a category of tools ("Give me all registered JPEG viewers"). It receives a list of CLSIDs and chooses one based on user preference or priority.
  • Note on IIDs: Regardless of how the CLSID is found, the IID (the interface) which the app usually has already because it knows what it wants to do, in this example, printing even if the CLSID has just been identified. The IID is the 'Interface Contract' and is usually pre-defined in the application's code, ensuring that once the CLSID is activated, the app knows exactly which 'language' to speak to the object.
2. What type?
COM Runtime resolves the CLSID and identifies the Server Type.
  • In-Proc: Loads a DLL into the app's own memory.
  • Local/Out-of-Proc: Launches a separate EXE.
  • Remote: Uses DCOM to talk to a tool on another computer.
3. :)
4. Every COM object speaks a 'base language' called IUnknown. It only has three commands: AddRef, Release (to manage memory), and QueryInterface. When Hello Kitty asks for a printing pointer, it’s using that base language to see if the object can 'graduate' to the more advanced Printing language (IID).
Here QueryInterface(IID_**) is called
5. If QueryInterface succeeds, the object returns a Pointer (if the tool is in the same memory space) or a Proxy (if the tool is in a different process/PC). 
6. The app then uses this pointer to call the specific methods (like PrintNow()) defined in that interface's vtable.

The "Offensive" Approach (How Hacker's abuse COM Objects)

Case Studies

Attack 1 - Scheduled Task COM Hijacking

Possibly the most popular, and common is COM hijacking, used for a multitude of reasons such as persistence, payload execution and more. The primary advantage of COM hijacking is the ability to achieve execution or persistence within a medium integrity context, as the User Hive (HKCU) typically takes precedence over the System Hive (HKLM) in the 'search order'.

Note: Scheduled tasks are typically favoured, however Explorer Shell Extensions, UAC Bypasses and Environment Variables (and more) can also be abused in such a way, if you want to go down that rabbit hole, simply utilising ProcMon and finding Phantom COM Objects is a great way to start; this can be done by hunting for NAME NOT FOUND within a RegOpenKey.

Here is extra reading material on other methods of hijacking.

This is covered inside the MITRE ATT&CK Framework as T1546.015.

For the initial example, I'll perform this using the GUI alone to demonstrate it, as well as a practical example of how straightforward it is to abuse this. The primary goal here is to review tasks that are utilising Com Handlers / Objects

First we must enumerate Scheduled Tasks, I found some very old scripts for this that didn't seem to work anymore, so a quick revised one I've put together can be found here. This will identify tasks that are utilising COM Handlers as opposed to executable paths (in the action field).

Upon execution on a fresh Win11 VM we receive the following output.

Script output


This provides a wealth of information to allow us to target different tasks for 'sneaky' persistence, as a typical sweep by the security team (if the hypothesis was driven towards such mechanism) would be of the scheduled tasks content itself - modification etc, it is worth noting with the right tools this is super trivial and may require some 'advanced' methods to circumvent easy detection.

First, we want to research and identify a task that will not crash the system and give away that something is amiss, for this I will target SystemSoundsService.

For the HKLM key, we would require the TrustedInstaller group, which may be an issue.
However, we can simply duplicate the entry within HKLM to HKCU which will take priority in the 'search order'. (Even if it didn't exist prior) as the HKCU is checked prior to the HKLM.

It is worth noting, Ghost objects are preferred because since the original CLSID doesn't point to a real DLL, your hijack doesn't break any existing system functionality, it only adds your own.
Below we can see the entry inside HKLM.

HKLM entry

By taking this data and placing inside HKCU, our entry is 'first' in the search order when the COM runtime checks the Registry for the reference.

By redirecting the InprocServer32 subkey to a 'malicious' DLL, we can intercept the instantiation of the target object.

Hijacked entry example


It is worth mentioning, I am of course targeting x64 space, for x32 it is within the HK**\%Wow6432Node\CLSID%
For the 'payload' a simple calc spawner
leet calc.exe spawner


This can simply be automated further with a secondary script ingesting relevant parameters and hive paths and further development for a 'lookup' list that identifies a list of known DLLs and targets them, however this adds additional forensic residue.

However for now, we will manually modify the path (again, requiring relevant permissions) and relogin.

The results

Upon a new login (as targeted in the Triggers) we see calc get executed.
Upon a quick glance, an analyst may review the tasks content, and simply see the CLSID and believe it benign, this also removes any modification/residue within the scheduled task itself, as all of the changes have been made within the Registry.

Persistence (??) achieved!

It should be noted, taskhostw.exe is used to invoke this, hence some limitations for more interesting abuses.

Last note: This is definitely a trial and error process that's worth testing beforehand, I had quite the arm wrestle attempted to get a stable C2 off this as I was essentially faced with race conditions and Control Flow Guard (CFG) ruining my day, as a result I vibe-coded together a 2 part simple C2 framework with the payload having an exported COM interface.

Here is a horrendously cut video I created showing the persistence. (no connection received ping ftw)



As mentioned above, there is a lot of caveats to achieving this, finding the right target can mean the difference between

  • Facing inconsistency due to race conditions
  • Blocked by security features (especially if you intend to migrate to another process).

Detection 1 - Hijacking

The host has Defender disabled and Sysmon installed, the rest is out of the box stuff.

Sysmon primarily is to replace the visibility provided by an EDR, however how this can be found without 'enhanced telemetry' through the use of forensics will be discussed.

NTFS

Here we can quickly review the MFT/UsnJrnl, DLLs are overlooked because systems can be so noisy.

A simple filter for .DLL shows 2 things, my many trials, errors and successes, and a glimpse of how noisy DLLs can be.

Of course, we can filter on specific file paths, but simply excluding something like... System32 opens up a potential blindspot. If the file was deleted for cleanup, of course we can review the UsnJournal or further.

Sysmon (ETW) ~ EDR


Not here to debate, but on a budget it does the detection job very well out of the box; I am sure if you have/do work in DFIR, there is times you wished Sysmon was on the system.


I will not strife through all of these, as they can quite quickly be identified, anomalous network connections, image loaded and due to the simplicty of the reverse shell, command execution (spawned directly through cmd.exe) was trivial to see in Event ID 1.

Recall, taskhostw.exe.

EVTX

So minus Sysmon, this was quite a 'test out of the box' experience, and to little surprise, zero entries outside of downloading the actual payload was picked up.

EventID 1 for Powershell download cradle


Registry

User Hives

The only remnants was simply inside the key that was targeted. (Additionally Shellbags, but this depends on how it was performed (using Powershell versus Registry Editor for example).

Amcache

Unfortunately, despite executing through 2 separate binaries, no entry was created. It would appear taskhostw does not inventory DLLs.

Persistence One Stop Shop

SysInternal's Autoruns easily snags this due to the file being unsigned.

However, with the use of a signed binary or more meticulous steps, subverting such a thing would be possible.

Evidence of Execution
(Of course excluding Sysmon and 4688 which is < Sysmon)

Prefetch
First that came to mind (outside of our Sysmon EID 1), now in this attack, TaskHostW.exe will be the 'target' process, by inspecting the loaded modules (captured within the first 10~ seconds of execution) we find the following.



There is a variety of other methods, however these correlate quite well, what I spent a bit of my time on here was the Amcache, of course for the hash, no entry occured. Also as a caveat, if dealing with this on a live host, process analysis (through something like ProcMon/Process Hacker/Memory Analysis) will of course bare a lot of fruit. 

Attack Example 2 - DCOM Lateral Movement

DCOM (Distributed Component Object Model) is a proprietary Microsoft technology that extends the Component Object Model (COM) to allow software components to communicate across a network. Think of COM as a way for applications on the same computer to talk to each other (like Excel talking to Word). DCOM is the 'bridge' that allows that same communication to happen between different computers on a network.

Despite this technique being documented quite well, I think it is a great example of activity not observed so often, the following 4 commands alone perform remote code execution on the specified IP address (requiring specific permissions, of course:) ). (in this case, spawns calc)
  1. $target = "10.111.111.7"
  2. $t = [type]::GetTypeFromProgID("MMC20.Application.1", $target)
  3. $a = [System.Activator]::CreateInstance($t)
  4. $a.Document.ActiveView.ExecuteShellCommand("cmd.exe", $null, "/c calc.exe", "7")
It is worth noting, the process will spawn in session 0, which can absolutely be weaponised, but potentially limiting depending on the use case.

Let's say for this instance, we have a remote share (I'll just use the target host itself for this **imagination -> Desktop = CorporateShare**) with a RAT or anything alike, and we want to execute it on the remote system but some of the traditional lateral movement techniques are either not possible, or too risky (noisy).

In this case, we will use the same DLL as Attack 1.

Commands example

So with the above, the setup (querying the remote registry to find the CLSID of the MMC20.Application COM Object, followed by remote instantiation (DCOM activation). Followed by commandlet building and execution.

As observed below, as opposed to the persistent method used above, this provides RCE and a stable reverse shell.



This naturally can be weaponised much further.

Detection 2

What is most interesting here, is the fact that the establishment (between client A and client B) is performed through mmc.exe

This of course using Network Event in Sysmon (Network Telemetry, EDR, Sysmon pls)



Wherein the parent process is svchost.exe

We can pivot off the source port seen in the mmc.exe screenshot to identify the login (this is of course type 3)



4672 (privileged login) cannot be identified through the port alone, use the logon ID.


From here reviewing anomalous child processes of mmc.exe provides a clear indication of what has occured.

Of course, if these aren't available further sources such as evidence of execution, file existence, through disk and memory forensics can be performed, but I feel it is out of scope, plus this post is getting quite lengthy.


Attack Example 3 - Execution through CLSID reference (evasion)

Simply because it's interesting, and I believe there is a risk of people coming across a log entry and thinking "this is typical Windows..." *slams close as FP*.

This more so lingers on the side of living of the land / defense evasion.

So what's happening here?

explorer shell:::{645FF040-5081-101B-9F08-00AA002F954E}



As you can see, simply referencing the CLSID we can run a process, with the previous segments of the blog in mind, we know we can add entries, and point it to whatever we want.

So, it is simple enough to hide and bypass detection rules riddled with 'cmdline = *..*...*...*.***'


ty

Comments

Popular posts from this blog

Velociraptor Dead-Disk Forensics

Velociraptor MCP