Beacon Object File(BOF) cs 4.1后添加的新功能,
Beacon在接收执行obj前,Cobalt Strike会先对这个obj文件进行一些处理,比如解析obj文件中一些需要的段.text,.data,在处理一些表比如IMAGE_RELOCATION,IMAGE_SYMBOL等等,然后在经过一系列的处理后,会把需要的部分按照一定格式打包起来随后在发送给Beacon,这时Beacon接收到的是Cobalt Strike已经解析处理过的obj文件数据,并非是原本的obj文件,所以Beacon主要做的是必须是在进程内才能确定并完成的事情比如处理重定位,填充函数指针等等,最后去执行go入口点
obj 目标文件就是源代码编译之后但是未进行链接的那些中间文件(Windows 下的 .obj 和 Linux 下的 .o,本文主要指windows 下的 obj )
使用BOF框架开发
很多大佬在 GitHub 发了一些模板,可以去参照
- bof的visual studio模板:https://github.com/securifybv/Visual-Studio-BOF-template
- bof所需的头文件:https://github.com/trustedsec/CS-Situational-Awareness-BOF
- 整理好的,通过DLL名称将WindowsApi函数进行了归类:https://github.com/evilashz/Visual-Studio-BOF-template
将下载的模板文件解压至visualstudio的模板目录(%UserProfile%\Documents\Visual Studio 2022\Templates\ProjectTemplates
),随后重启VisualStuido
在创建项目时选择类型为Beacon Object File
的项目
在头文件列表可以看到beacon.h
和bofdefs.h
build->batch build 打开项目的 Batch 生成,勾选上 BOF 配置
配置管理器的编译环境也需设置为BOF
一个简单的 bof 项目,用于实现向控制台输出字符串
- BOF 入口:代码定义了 BOF 的入口函数 go,当你在 Cobalt Strike 中使用 inline-execute 命令加载并执行你的 BOF时,这个函数将被调用。你可以在这个函数中添加你的 BOF 代码
- 非 BOF 入口:这部分代码定义了非 BOF 的入口函数 main。当你在非 Cobalt Strike 环境中运行你的代码时,这个函数将被调用。你可以在这个函数中添加你的非 BOF 代码
1 |
|
项目生成后会生成一个.obj
文件,也就是编译未链接的目标文件,在CobaltStrike中你可以使用inline-execute
命令来加载并执行你的.obj文件,此命令将你的 .obj
文件加载到 Beacon 的内存中,然后调用你的 go
函数,命令格式如下所示
1 | beacon> inline-execute your_bof.obj |
修改为BOF格式
在原有利用代码基础上修改为 BOF 代码步骤
- 引入 beacon.h 头文件,beacon.h 定义了与 Cobalt Strike Beacon 交互所需要的各种数据类型和函数
- 把所有字符串和函数改成 ascii 的
- 把所有函数改成 beacon.h 定义的编写约定
- 入口函数由 main 修改为 go
- 生成 bof 文件
将 get-computer-installed-software 修改为 bof 加载,代码通过查询注册表获取当前机器安装的程序,这种方式仅对完整安装的软件有效,如果是绿色版的软件则只能通过手工或自动化搜索的方式查找,如果是x64位系统则需要对32位程序也进行遍历(x64系统存在注册表重定位)
1 |
|
接下来导入 beacon.h 和替换 BOF 约定的写法,函数原型使用 bof_helper 自动化帮我们生成好bof约定的函数原型和写法,如把 GetProcAddress 换成 KERNEL32$GetProcAddress 的写法,这里直接使用工具,同时也需要把输出函数换成 beacon 导出的函数
BOF 格式代码
1 |
|
其余的 bof 格式差异
参数传入
目前代码没有传入参数,如果有参数传入,需要先声明参数
1
2
3
4
5
6
7void go(char* args,int length){
datap parser;
char* str_arg;
int num_arg;
str_arg = BeaconDataExtract(&parser,NULL);
}输出
使用 BeaconPrintf 替换 printf
1
BeaconPrintf(CALLBACK_ERROR,"ERROR");
编译
使用 gcc 进行编译,需要提前安装
1 | gcc -c 源文件.c -o 输出文件.o |
ps:注意需要安装 64 位的程序,才能编译 64 位的 obj 文件,MinGW-w64安装教程
inline-execute 在 cs 中直接使用 bof 文件
bof 缺点
- 似乎无法使用初始化为0的全局变量
- 不太适合跑驻留型的任务,跑大量循环会崩溃
- 一旦引发崩溃整个beacon就会崩掉
- 不易调试
- 似乎输出不能使用unicode
参考文章