初探 Cobalt Strike BOF
2024年8月23日大约 2 分钟
初探 Cobalt Strike BOF
注
本文版权归原作者所有,未经允许禁止转载。
前言
本文参考了以下两篇文章:
https://cloud.tencent.com/developer/article/2428694
https://wbglil.gitbook.io/cobalt-strike/cobalt-strike-yuan-li-jie-shao/untitled-3
BOF 代码基础
官方 BOF 模板:https://github.com/Cobalt-Strike/bof-vs
我看网上好像有不同版本的 BOF 模板,调用 API 时是这种形式:KERNEL32$XXX
,在目前的官方模板中,如需调用 API,则需提前声明:DFR_LOCAL(KERNEL32, WinExec);
简单介绍下代码:
调用 API:
DFR_LOCAL(KERNEL32, WinExec);
在 beacon 中输出:
BeaconPrintf(CALLBACK_OUTPUT, "Hello BOF!");
解析命令行参数:
datap parser;
LPWSTR arg1;
LPWSTR arg2;
// ... LPWSTR argn;
// 初始化datap结构体变量(parser),用于解析从Beacon接收到的字节流(buff)
BeaconDataParse(&parser, args, len);
command = (LPWSTR)BeaconDataExtract(&parser, NULL);
BeaconPrintf(CALLBACK_OUTPUT, "arg1: %S", command);
BeaconPrintf(CALLBACK_OUTPUT, "arg2: %S", command);
// ...
// BeaconPrintf(CALLBACK_OUTPUT, "argn: %S", command);
有了上面这些基础,BOF 的编写就相对简单了。稍微更正一下,替换 go 函数即可:
void go(char* args, int len) {
/**
* Define the Dynamic Function Resolution declaration for the GetSystemDirectoryA function
* This time we use the DFR_LOCAL macro which create a local function pointer variable that
* points to GetSystemDirectoryA. Therefore, we do have to map GetSystemDirectoryA to
* KERNEL32$GetSystemDirectoryA
*/
DFR_LOCAL(USER32, MessageBoxW);
datap parser;
LPWSTR tips;
LPWSTR msg;
// 初始化datap结构体变量(parser),用于解析从Beacon接收到的字节流(buff)
BeaconDataParse(&parser, args, len);
tips = (LPWSTR)BeaconDataExtract(&parser, NULL);
msg = (LPWSTR)BeaconDataExtract(&parser, NULL);
BeaconPrintf(CALLBACK_OUTPUT, "tips: %S", tips);
BeaconPrintf(CALLBACK_OUTPUT, "msg: %S", msg);
MessageBoxW(0, msg, tips, 0);
}
有几个注意的点:
参数传递注意编码,需要使用
WCHAR
,也就是LPWSTR
宽字符,不然不能正确接收参数,猜测是编码问题。尽量不要在栈上分配内存,会触发缓冲区溢出检查,导致链接一些 CRT 内置函数,BOF 没法执行。
调用一些函数时可能会阻塞,如 MessageBox,会影响 beacon 的运行。
再参考文章编写一个 cna 文件,用于 CS 加载:
beacon_command_register(
"msg",
"call MessageBoxW",
"usage: msg <tips> <msg>");
alias msg{
local('$handle $data $args');
$tips = $2;
$msg = $3;
if ($tips eq "" or $msg eq "") {
berror($1, "usage command: help msg");
return;
}
# 读入bof文件
$handle = openf(script_resource("msg.x64.o"));
$data = readb($handle, -1);
closef($handle);
# 打包参数两个ZZ代表两个参数
$args = bof_pack($1, "ZZ", $tips,$msg);
# 执行bof
# "go"是BOF中的函数名,$args是传递给这个函数的参数
beacon_inline_execute($1, $data, "go", $args);
}
放在同一目录下,加载执行,测试一下效果:
