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

有几个注意的点:

  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