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"

DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);

void go(char * args, int alen) {
DWORD dwRet;
PDOMAIN_CONTROLLER_INFO pdcInfo;

dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
if (ERROR_SUCCESS == dwRet) {
BeaconPrintf(CALLBACK_OUTPUT, "%s", pdcInfo->DomainName);
}

NETAPI32$NetApiBufferFree(pdcInfo);
}

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.