如何编写BOF
什么是BOF
BOF的全称是Beacon Object File。它一个使用C语言编写,运行在Beacon进程空间内,并且调用Beacon API的一段函数代码。其本质上是一个对象文件。
总所周知,从源代码到可执行程序要经历4个阶段。
预编译 -> 编译 -> 汇编 -> 链接
在源代码按照此流程经历过汇编之后,会生成一个共用对象文件格式(COFF)的文件,也就是目标文件或对象文件。由于缺少链接过程,该文件无法直接使用,需要修补程序中调用的Win32 API函数的内存地址等信息,这部分工作由beacon完成。
为什么要用BOF
Cobalt Strike中集成了多种执行自定义功能的方法,如:反射DLL注入,PowerShell和.NET等。通常情况下以上方法会触发向其他进程内存写入数据的行为,这会触发EDR告警。而BOF的执行是插入在beacon自身进程中,从而规避监测。
BOF编写
引用beacon.h
文件地址:beacon.h
在beacon.h中定义了beacon的接口,如:传入参数、显示结果等。而且在使用不同版本的Cobalt Strike时,需要注意使用的Beacon API是否与之适配。
调用Win32 API函数
在调用Win32 API前,需要对函数重新定义,方法如下
1 | WINBASEAPI <return_type> WINAPI <dll_name>$<function_name> (<parameters>) |
例如我需要在BOF中调用 HeapFree
,则需要进行如下定义
1 | WINBASEAPI void * WINAPI KERNEL32$HeapFree (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); |
调用libc函数
在使用libc函数时也需要定义,方法与调用Win32 API函数大致相同。这里直接通过举例说明
1 | WINBASEAPI void * __cdecl MSVCRT$malloc(size_t _Size); |
编写代码
通常情况下入口函数为 void go(char * args, int alen)
。当然也可以将入口函数修改为其他名字,但是在调用的时候需要指定入口函数名。
编译BOF
编译器使用mingw-w64
macOS夸平台编译
brew install mingw-w64
1 | i686-w64-mingw32-gcc -c bof.c -o bof.x86.o |
cna脚本调用
1 | $handle = openf(script_resource("bof. $+ $barch $+ .o")); |
$bid
: beacon ID$data
: BOF文件"go"
: 入口函数名$args
: BOF参数
最后
在编写BOF时,特别需要BOF的崩溃。由于BOF是插入到beacon中执行,所以BOF的崩溃会直接导致beacon进程中止,且BOF不适用长期运行的功能,如网络扫描、代理等。