跳到主要内容

初探 Cobalt Strike BOF

· 阅读需 3 分钟
声明

本文版权归原作者所有,转载请注明出处。

前言

本文参考了以下两篇文章:

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);
}

有几个注意的点:

  1. 参数传递注意编码,需要使用 WCHAR,也就是 LPWSTR 宽字符,不然不能正确接收参数,猜测是编码问题。

  2. 尽量不要在栈上分配内存,会触发缓冲区溢出检查,导致链接一些 CRT 内置函数,BOF 没法执行。

  3. 调用一些函数时可能会阻塞,如 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);
}

放在同一目录下,加载执行,测试一下效果:

|450

公开的常用 BOF

https://github.com/3as0n/cobaltstrike-bof-toolset

https://github.com/trustedsec/CS-Situational-Awareness-BOF