AI 生成 | Cobalt Strike 4.13 Lost in Translation — Beacon Interpreter 仓库源码解读
原创
GLM-5.2
GLM-5.2
赛博生存指南
2026年6月19日 16:43
浙江
在小说阅读器读本章
去阅读
Cobalt Strike 4.13 的 Beacon Interpreter要终结,编译、上传、执行、翻 Beacon Console 看报错、再编译的BOF反馈循环。
2026 年 6 月 10 日,Fortra 发布 Cobalt Strike 4.13,代号 \"Lost in Translation\"。
这是个一语双关的标题:既是经典电影《迷失东京》的英文原名,也精准概括了本次更新的核心主线——「翻译/转换」。Teamserver 把 C 翻译成字节码、BOF-PE 让原生 PE 格式在 Beacon 里翻译运行、Beacon 自身从 MSVC 向 LLVM 工具链迁移……整整一个大版本,都在解决「如何把更高层的代码,翻译进那个本该轻量的 Beacon」。
本文先拆解官方博客里 4.13 的全部更新,再结合 Fortra 同步开源的 beacon-interpreter 仓库做一次源码级解读——它正是 Beacon Interpreter 的官方开发支持包。
一、4.13 都更新了什么
| 模块 | 更新 | 一句话价值 |
|---|---|---|
| Beacon Interpreter | Beacon 内置 C 脚本 VM | 不再需要分配内存,直接在 Beacon 里跑 C |
| BOF-PE | 支持原生 DLL/EXE 格式 BOF | 可用错误处理、C++、外部库,甚至 Rust |
| LLVM Beacon | 基于 LLVM 的新 Beacon | 更小 payload,下版本弃用 MSVC Beacon |
| Payload Store | payload 集中存储 + 版本控制 | 每个 Beacon 可追溯到具体导出版本 |
| Malleable Profile Overrides | .mpo 覆盖文件 |
改 C2 设置不再需要重启 Teamserver |
| REST API | WebSockets + gRPC 流式 | 取代状态轮询,生态集成更顺 |
| UX | docking / 自定义表格 / 新字体 | LDAP 查询结果可渲染成可交互表格 |
| 凭证管理 | 控制台高亮入库 + 右键动作 | Kerberos 票据处理流程大幅简化 |
其中前两项 Beacon Interpreter 和 BOF-PE 共同构成了博客所说的 \"Post-Ex Evolution\"(后渗透演进),是这次的重头戏。
二、为什么是现在:BOF 被推到了极限
要理解 Beacon Interpreter 的分量,得先回顾 BOF(Beacon Object File)的设计初衷。
BOF 是 Cobalt Strike 创始人 Raphael Mudge 提出的抽象——本质上是在位置无关代码(PIC)之上,恢复了少量便利(动态函数解析等)。它从设计上就是轻量、低开销、即用即走:Beacon 拿到 BOF,分配一块内存、加载、执行、释放。
但十年下来,使用者把这套设计逼到了墙角:
- 1. 想要更高层的抽象却得不到——比如异常处理,BOF 基本不支持。想写复杂 tradecraft 的操作者非常痛苦。
- 2. 工作流本身很笨重。最讽刺的例子:你写一个 BOF 只是为了释放内存,Beacon 为了执行它,还得再申请并释放一块内存。
4.13 的解法是双管齐下:Beacon Interpreter 解决\"轻量脚本\"场景,BOF-PE 解决\"复杂 tradecraft\"场景。
三、Beacon Interpreter:让 Beacon 直接解释执行 C
工作原理
当你运行一个 Beacon Interpreter 脚本(比如 helloworld.c),流程是这样的:
helloworld.c
│
▼ Teamserver 端编译
中间字节码 (bytecode)
│
▼ 随 C2 任务下发
Beacon 内置 VM 解释执行
│
▼ 通过 FFI 调用
Windows API / BOF API
两个关键设计决定了它的全部特性:
- • VM 是 Beacon 原生的。执行时不需要额外分配内存,也不改变既有内存的权限——这直接抹掉了 BOF 最大的内存检测面。
- • 编译在 Teamserver 端完成。用户不再需要本地编译 C 脚本(不像 BOF 那样要
x86_64-w64-mingw32-gcc一通操作)。
这个 VM 最初基于开源的 picoc 项目,但 Fortra 对其做了大幅重构和扩展以适配 Beacon 的需求。
四种交互方式
| 入口 | 用途 |
|---|---|
beacon-interpreter 命令 |
Beacon 控制台直接执行 |
bbeacon_interpreter |
Aggressor 脚本函数 |
| REST API | 程序化集成 |
| Script Editor(IDE) | GUI 内置编辑器,近实时反馈 |
Script Editor 的诞生动机很真实:Fortra 团队自己 dogfooding 时,被 BOF 那条 \"写→编译→重跑→看 Console→循环\" 的慢反馈折磨够了,于是把 IDE 直接塞进了客户端。现在可以在客户端里开发能力,近乎即时看到结果。
与 Windows API 的桥梁:BOF 风格 DFR
Interpreter 的 C 子集贴近 C89/C99,但调用 Windows API 时有个门槛——VM 必须知道怎么调。解法是沿用 BOF 的 DFR(Dynamic Function Resolution)函数定义语法:
KERNEL32$LoadLibraryA: ptr (ptr);
声明之后,LoadLibrary 就能像写普通 Windows 程序一样使用了。Teamserver 还自带了一批常用头文件,通过标准 C include 引入,例如 #include <msvcrt.h> 拿到微软 C 运行时,#include <beacon.h> 拿到完整 BOF API,#include <internal.h> 里的 DbgPrintf 还能用 DebugView 调试。
注意:这些头文件不是与 Windows SDK 的 1:1 映射,会有缺口。需要补充时,把自定义头放进
server/interpreter/includes/user目录即可被立即识别。
最后,Fortra 把这套开发支持包开源到了公开 GitHub——也就是本文后半部分的源码分析对象。
四、源码分析:官方开源的 beacon-interpreter 仓库
仓库地址:https://github.com/Cobalt-Strike/beacon-interpreter
注意:这里开源的是开发支持包(头文件 + AI 指南 + 示例),不是解释器/VM/编译器的实现。VM 本体闭源在 Teamserver 中。
项目概览
| 项目 | 详情 |
|---|---|
| 角色 | Beacon Interpreter 脚本开发支持包 |
| 组成 | skills.md (AI 生成指南)+ interpreter_demo.c(示例)+ interpreter-includes/(头文件集) |
| 头文件规模 | 34 个文件,约 10,500 行 |
| 许可证 | Apache 2.0 |
| 最大的头 | winnt.h (2,659 行)、winbaseapi.h(1,075 行) |
三大组成
1. skills.md(357 行) —— 写给 AI agent 的兼容性规则。这是最有意思的一份文档:Fortra 显然预期到大量 Interpreter 脚本会由 AI 生成,于是直接把 VM 的所有\"坑\"明文写了下来。
2. interpreter_demo.c(223 行) —— 一份\"特性考试题\",系统性演练了链式赋值、逗号表达式、三目运算、位运算、while/do/switch/goto、数组与指针算术、__builtin_offsetof、链表、union 字节拆分、u64/i64、宽字符,以及原生 API 的直调与函数指针调用。
3. interpreter-includes/ —— 头文件分三层:
- • 聚合层:
windows.h仅 includewinnt/winbaseapi/winerror/msvcrt(用BUILTINS_WINDOWS_H这类 guard,提示是 CS builtins 头的精简镜像) - • 基础类型层:
wintypes.h定义DWORD/HANDLE/SIZE_T等,并用_WIN32宏切换指针大小 - • 各 DLL 的 FFI 声明层:
advapi、ntapi、msvcrt、psapi、winsock2等逐库组织
VM 执行模型:三个反直觉点
skills.md 反复强调,这不是标准 C 运行时:
- 1. 没有隐式
main()。顶层语句就是入口;定义了main()还要自己显式main();调用(demo 里run_demo()在文件末尾被手动调用)。 - 2.
__argc/__argv不是 POSIX 参数。这是新手最大的坑:
读取方式完全同 BOF,要用 BeaconDataParse / BeaconDataExtract:
if (__argc > 0) {
datap args = {0};
BeaconDataParse(&args, __argv, __argc);
char *message = BeaconDataExtract(&args, NULL);
// ...
}
- •
__argc= Beacon 打包参数缓冲区的字节数 - •
__argv= 指向该缓冲区的指针
- 3. 小端字节码假设,运行时容量有限(栈、调用深度、局部/全局变量数都有上限)——禁止无界递归和超大局部状态。
C 子集与限制
支持常规 C 的大部分,但有一组硬限制,且这些限制彼此呼应:
| 限制 | 说明 / demo 如何规避 |
|---|---|
无 float/double |
只能用整数/定点 |
void * 不可直接解引用/下标 |
demo 里 ((int *)vp)[0] 先转型 |
| 脚本函数不支持变参,也不能经函数指针调用 | demo 的 GETPID_FN 调用的是原生 FFI 指针,合法 |
| struct 按值传参/返回受限 | 优先用指针传递聚合类型 |
| 宏非完整预processor | 复杂逻辑改用普通函数 |
| 声明符须保守 | 避免异形函数指针声明 |
FFI 契约:整套自己的函数签名语法
这是整个体系最特别的地方,沿用 BOF DFR 风格:
KERNEL32$GetLastError: u32 (); // LIB$Function: 返回类型 约定 (参数...)
MSVCRT$printf: cdecl i32 (cstr, ...); // cdecl + 变参
USER32$GetDesktopWindow: ptr (); // demo 中自定义签名
规则:
- • 约定:
cdecl/stdcall/ 省略(省略=stdcall)。变参仅cdecl合法。 - • 64 位脚本约定可省;32 位 VM 必须指定,否则崩溃。
- • 原子类型表(注意:没有浮点,呼应上面的限制):
| 类型 | 含义 |
|---|---|
void |
无返回值 |
i16 / u16 |
16 位有/无符号 |
i32 / u32 |
32 位有/无符号 |
i64 / u64 |
64 位有/无符号 |
ptr |
指针 |
cstr |
C 字符串(等价 ptr,推荐用于字符串形参) |
size_t |
对齐 Windows SIZE_T,指针大小 |
beacon.h 的隐藏威力:暴露 Beacon 内部运行时
beacon.h(267 行)是这套头里信息量最大的,内容分两组:
公开 API(常规):BeaconDataParse/Extract(参数解析)、BeaconPrintf/Output(回调输出)、BeaconFormat*(格式化缓冲)、Beacon*Process(注入/派生)、BeaconUseToken/RevertToken(令牌)、BeaconVirtualAlloc/Protect/...(Beacon-gate 包装的内存 API)。
内部数据结构(高级,这才是亮点):
typedef struct _SYSCALL_API_ENTRY {
PVOID fnAddr;
PVOID jmpAddr;
DWORD sysnum; // ← 直接拿到 syscall number
} SYSCALL_API_ENTRY;
typedef struct _BEACON_INFO {
unsigned int version;
char * sleep_mask_ptr;
// ... sleepmask / beacon 内存布局
ALLOCATED_MEMORY allocatedMemory;
} BEACON_INFO;
SYSCALL_API 直接暴露了 NT 系统调用号与跳板地址,ALLOCATED_MEMORY 暴露了 sleepmask 的内存区域布局,BEACON_INFO 暴露了 Beacon 自身指针。这意味着 Interpreter 脚本的能力远超普通 BOF——能直接做 direct syscall、读写 Beacon 内存、自定义 sleepmask、操作数据存储(Data Store)。换句话说,脚本可以深入操作 Beacon 自身运行时。
输出与大缓冲
skills.md 专门叮嘱:BeaconPrintf 用于状态/摘要,不要在紧凑循环里高频调用;大量数据应走 BeaconFormat 流程(Alloc → Printf → ToString → Free)分块输出,避免压垮 Cobalt Strike 客户端。
五、同台对比:BOF / BOF-PE / Beacon Interpreter
| 维度 | 传统 BOF | BOF-PE(4.13) | Beacon Interpreter(4.13) |
|---|---|---|---|
| 代码形态 | 位置无关 COFF | 原生 DLL/EXE | C 源码,Teamserver 编译字节码 |
| 内存开销 | 需分配/释放内存 | 需加载 PE | 无需额外分配内存 |
| 高级特性 | 弱(无异常处理) | 强(C++/异常/外部库) | 中(C 子集,无浮点) |
| 本地编译 | 需要 | 需要 | 不需要 |
| 反馈循环 | 慢 | 慢 | 快(Script Editor 近实时) |
| 适用语言 | C | C/C++/Rust | C |
| 复杂 tradecraft | 受限 | 最强 | 中等 |
三者并非替代关系,而是分工:Interpreter 管\"快速、轻量、无内存抖动\"的脚本场景,BOF-PE 管\"复杂、需要完整语言特性\"的重量级场景,BOF 继续兜底。
六、从防御视角看 Beacon Interpreter
对蓝队而言,这次更新值得认真对待。博客里一句不经意的话,其实是给防御方的核心提醒:
As the VM is native to Beacon, it does not need to allocate any additional memory (or fluctuate the memory permissions of previously allocated memory).
这句话翻译成检测语言就是:围绕\"内存申请 + RWX 权限变更 + 执行\"这套经典 BOF 检测链,对 Interpreter 脚本可能整体失效。脚本不再在堆上落一块可执行内存,而是跑在 Beacon 既有的 VM 解释器里。
但盲区不等于隐身。新的检测面在别处:
- 1. 字节码特征。脚本要先被 Teamserver 编译成中间字节码、随 C2 任务下发。这套自定义字节码指令集本身,以及它在 C2 流量里的形态,是新的识别维度。
- 2. 解释器驻留。VM 本体是 Beacon 的常驻代码,无论脚本是否运行都存在,可作为静态特征。
- 3. FFI 调用边界。脚本能力再强,最终调用 Windows API 时仍要经过
LIB$Func解析,API 调用行为(尤其beacon.h暴露的SYSCALL_API、内存操作类 API)仍是行为监控的着力点。 - 4.
checkin_delay。4.13 新增的 Malleable C2 选项,用于打乱反射加载与首次元数据交换的时间关联——这也提示蓝队:加载时机与首次回连的时间相关性,本身就是一条检测线索。
一句话:Interpreter 把内存层面的噪声降到了最低,代价是把战场从\"内存权限\"转移到了\"字节码与 C2 流量\"。
结语
\"Lost in Translation\" 是个恰如其分的代号。4.13 这一整版都在做同一件事:把更多、更高层的代码,翻译进那个曾经只愿接纳 PIC 的 Beacon。
对红队,Beacon Interpreter 消灭了 BOF 的内存抖动和缓慢反馈,Script Editor 让能力开发像写脚本一样轻;对防御方,熟悉了十年的\"BOF 申请内存→改权限→执行\"检测模型正在被悄悄架空,新的战场在字节码和 C2 流量里悄然展开。
官方同时开源开发支持包、还专门写了 skills.md 给 AI 看——这个信号也很明确:未来的 Interpreter 脚本,大概率大半是 AI 生成的。攻防双方,都得开始熟悉这套新的「翻译」规则。
本文基于 Cobalt Strike 官方 4.13 发布博客与公开开源的 beacon-interpreter 仓库撰写,仅作技术研究与防御教育用途。
参考资源
- • Cobalt Strike 4.13: Lost In Translation — 官方博客[1]
- • beacon-interpreter — 官方开源仓库(GitHub)[2]
- • BOF-PE 参考实现(@CCob 提出,现由 NetSPI 维护)[3]
引用链接
[1] Cobalt Strike 4.13: Lost In Translation — 官方博客: https://www.cobaltstrike.com/blog/cobalt-strike-413-lost-in-translation
[2] beacon-interpreter — 官方开源仓库(GitHub): https://github.com/Cobalt-Strike/beacon-interpreter
[3] BOF-PE 参考实现(@CCob 提出,现由 NetSPI 维护): https://github.com/NetSPI/BOF-PE
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论