mwnickerson/certighost-bof
GitHub: mwnickerson/certighost-bof
针对 CVE-2026-54121 的最小化 Windows x64 Beacon Object File,在内存中通过 COM 接口向 AD CS 提交 PKCS#10 证书请求并返回签发结果。
Stars: 8 | Forks: 0
# Certighost BOF
此仓库包含一个极简的 Windows x64 Beacon Object File,用于 Certighost / CVE-2026-54121 实验链中仅涉及注册(enrollment)的部分。该 BOF 通过 `ICertRequest::Submit` 提交调用方提供的内存中 PKCS#10 请求(使用 `CR_IN_BINARY | CR_IN_PKCS10 | CR_IN_RPC` 参数),随后通过 Beacon 输出返回配置结果(disposition)、请求 ID 以及已签发证书的 base64 文本。
运行:`certighost-bof-20260727T143312Z`
这是 REDANTONETTA 仅限实验室的工作。未经授权,严禁推送、发布、部署或针对实时目标执行。
## 范围
该 BOF 仅实现 AD CS 注册追踪(chase)触发器。它不会创建计算机帐户,不会托管恶意的 SMB/LSA 或 LDAP 回调服务,不会生成 CSR,不会执行 PKINIT,不会写入 PFX/ccache 文件,不会恢复哈希,不会派生进程,也不会在目标侧写入任何文件。CSR、请求属性、返回的证书以及临时的 BSTR/base64 缓冲区均保留在内存中;分配的缓冲区在实际情况允许下会在释放前被清除。
[研究笔记](docs/research/CVE-2026-54121.md) 中描述的恶意 SMB/LDAP 回调服务是外部内存中的实验室先决条件。PKINIT 以及任何证书签发后的操作也是外部先决条件,在此特意不予实现。
## 参数结构(Schema)
`go` 入口点需要标准的 Beacon `bof_pack` 帧:一个小端序的 `u32` 有效载荷(payload)长度,后跟六个小端序且带有长度前缀的二进制字段。Apollo `execute_coff` v3 会原封不动地传递该帧:
```
$args = bof_pack($bid, "bbbbbb",
$csr_der,
$ca_config,
$template,
$san_dns,
$cdc,
$rmd);
```
字段按以下顺序排列:
| 字段 | 含义 | 验证 |
| --- | --- | --- |
| `csr_der` | DER PKCS#10 请求字节 | 非空,最多 256 KiB,有界的外部 DER `SEQUENCE` |
| `ca_config` | CA 配置字符串,例如 `ca01.lab.local\LAB-CA` | ASCII `host\CAName`,最多 512 字节 |
| `template` | 证书模板值 | 可打印的 ASCII,不含 `:`/换行符,最多 128 字节 |
| `san_dns` | 不含 `dns=` 前缀的 DNS SAN 值 | 可选的空字段,否则为类似 DNS/IP 的 ASCII,最多 255 字节 |
| `cdc` | 追踪回调主机/IP 值 | 必须为类似 DNS/IP 的 ASCII,最多 255 字节 |
| `rmd` | 远程域/主体查找 DNS 值 | 必须为类似 DNS/IP 的 ASCII,最多 255 字节 |
可移植解析器会验证规范的外部载荷长度、六个内部字段长度前缀、确切的字段数量以及尾部数据,然后 BOF 才会将完整帧传递给 `BeaconDataParse`/`BeaconDataExtract`。BOF 会在内存中构造以下确切的属性字符串:
```
CertificateTemplate:
SAN:dns=
cdc:
rmd:
```
只有当 `san_dns` 为空时,才会省略 `SAN:dns=` 行。
## 输出
签发时,BOF 会输出一个文本标头和一个 base64 框架的 DER 证书:
```
CERTIGHOST_RESULT disposition=3 request_id= cert_encoding=base64 cert_der_bytes= cert_base64_chars=CERTIGHOST_CERT_BEGIN
CERTIGHOST_CERT_END
```
Apollo 会将已签发的 `BeaconPrintf` 标头直接与下一个 `BeaconOutput` 标记聚合,因此规范导出的文本在 `cert_base64_chars=` 和 `CERTIGHOST_CERT_BEGIN` 之间没有换行符。任何输出字段都不是文件系统路径。对于被拒绝、挂起或失败的提交,BOF 会输出配置结果、可用时的请求 ID、可用时的最新状态 HRESULT,以及经过清理的 CA 配置结果消息。输入验证失败会在尝试 COM 注册之前发生。
## 前置条件
在此 BOF 之外的常规操作需要满足以下所有条件:
- 易受攻击的企业 CA 以及能够到达追踪路径的可注册模板。
- 已经拥有所选模板注册权限的 Beacon 安全上下文。
- 调用方生成的内存中 PKCS#10 请求,且与预期的请求者身份和 SAN 相匹配。
- 可访问的、仅限实验室的恶意 SMB/LSA 以及 LDAP 回调服务,用于提供 `cdc` 值。
- 任何后续的 PKINIT 处理、证书检查或证书签发后的验证操作均须在内存中单独执行。
## 构建与测试
```
make test
make bof
make lint
make imports
git diff --check
```
如果存在,`make bof` 会优先使用 `x86_64-w64-mingw32-gcc`。在此工作树中,它会回退到已安装的 LLVM clang 交叉编译目标路径,并以 `coff-x86-64` 格式输出 `build/certighost.x64.o`。`make test` 会构建并运行 macOS 主机测试套件(harness),以及离线的 Mythic 打包、任务模式(task-schema)、输出、文件系统证据、可重复性和清理测试。
## 恢复
如果 CA 返回未签发的配置结果,请保留报告的请求 ID 和 CA 消息作为证据,并在重新运行前更正实验室先决条件或请求输入。该 BOF 不会在稍后检索挂起的请求,不会持久化证书,也不会尝试任何改变目标状态的恢复操作。
## 研究
- [CVE-2026-54121 / Certighost 主要来源研究](docs/research/CVE-2026-54121.md)
## Mythic 集成
- [离线 Apollo execute_coff v3 工作流与证据验证](docs/mythic-integration.md)
## 实验室设计
- [REDANTONETTA 声明式实验室运行手册](docs/lab/CVE-2026-54121-redantonetta-runbook.md)
- [Ludus 靶场配置](ludus/ranges/redantonetta-certighost.yml)
- [本地 Certighost 实验室角色](ludus/roles/certighost_lab)
标签:AD CS, C/C++, log2timeline, 事务性I/O