peterhanily/ArtifactForge
GitHub: peterhanily/ArtifactForge
确定性合成取证工件生成器,通过独立解析器交叉验证确保跨工件哈希关联自洽,并附带用于评估取证调查能力的基准测试框架。
Stars: 0 | Forks: 0
# ArtifactForge
确定性、**经解析器验证**的合成取证 artifact —— 即响应者在深入排查后在主机上发现的文件 —— 与生成日志的 [EvidenceForge](https://github.com/Cisco-Talos/EvidenceForge) 的事件模型保持一致。
其核心是一个测试,而非断言。对文件字节进行一次合成,让每个 artifact 都能引用其真实的摘要,然后运行响应者实际使用的解析器 —— pefile、LIEF、regipy、libregf、libscca、macholib —— 并要求跨 artifact 的关联在它们的输出中成立。如果成立,则该场景在构造上就是一致的。如果不成立,这就是一个 bug。“逼真度”不再是一个主观偏好问题,而是一道非过即淘汰的关卡。
```
$ artifactforge bench new suite --n 4 --kind holdout
wrote 4 scenarios to suite (holdout suite)
key: suite/_key/key.hex
Lose it and this suite can never be regenerated or audited. Never commit it.
$ ls suite/scenarios/af1_a5pq7iqoumv3uglr
7zFM.exe Amcache.hve javaw.exe putty.exe
7ZFM.EXE-577AB7E4.pf certmgr_svc.exe notepad.exe PUTTY.EXE-F1C28886.pf
CERTMGR_SVC.EXE-8773131B.pf Software.run.hive
TASKENG_X.EXE-509F1868.pf
$ artifactforge bench solve suite --out answers.jsonl
wrote 4 submissions to answers.jsonl
$ artifactforge bench grade suite --submission answers.jsonl
count 2/2
enum 2/2
hash 6/6
imphash 4/4
name 4/4
path 2/2
url 2/2
SCORE: 22/22 = 100.0%
$ artifactforge gate identity
Gate 2 — identity: is every hash-shaped field a genuine digest of one ContentStore blob?
VERDICT: PASS (0 fail, 0 declared gaps) — 40/40 cross-artifact identity checks hold
```
上面的场景包含五个二进制文件。持久化机制启动了其中一个;Amcache 中记录的哈希值与其中*另一个*匹配;一条 prefetch 记录指向了一个已经不存在的程序。要解答关于它的任何问题都需要结合阅读两个 artifact,而这正是其目的所在。
## 包含内容
- **Windows artifact** —— 一个合成的 PE 文件,带有 pefile 计算出的真实、由种子确定的 IMPHASH;注册表 hive 包含 Run 键持久化机制和 Amcache 安装记录(`FileId` 确实是该文件的 SHA1);libyal 的 `libscca` 可以打开未压缩的 SCCA v17 prefetch,这意味着 plaso 能够读取它。
- **macOS artifact** —— 一个手工组装的 arm64 Mach-O 文件,带有真实的 symhash 和真实的 ad-hoc 代码签名(其 cdhash 可被 `codesign -d` 报告);knowledgeC、TCC 和 QuarantineEventsV2 数据库;`com.apple.quarantine` xattr 值;LaunchAgent plist。EvidenceForge 无法生成任何这些内容 —— 它的 `os_category` 只有 windows 或 linux,完全没有 macOS。
- **这一切背后的唯一身份。** `ContentStore` 对文件字节进行一次合成。任何地方任何哈希形式的字段都是这些字节的真实摘要,因此文件哈希关联能够工作,因为它不可能不工作。
- **用于调查而非召回的基准测试 —— 实验性质,且目前未通过其自身的有效性关卡。** 带有诱饵的确定性场景,每个问题至少跨越两个 artifact,答案派生自求解器永远看不到的测试套件密钥。基于密钥的测试套件部分有效;但场景组合存在信息泄露,对比 4.2% 的基准底线,其泄露得分高达 72.7%。详情请参阅下文的*它到底有多诚实?*。目前请勿报告从中得出的任何分数。
- **一个配套的适配器**,它可以读取 EvidenceForge 运行的输出,并还原其每个 Sysmon 哈希代表的具体逻辑二进制文件 —— 根据上游发出的摘要验证每一次还原,拒绝猜测而是直接报错。它从不导入 EvidenceForge。
- **四道关卡和一份记分卡。** 本文件中的每一项声明都映射到一个可以被监控并变红的关卡。请参阅 [`docs/DESIGN.md`](docs/DESIGN.md) §4。
## 试一试
```
uv venv && uv pip install -e ".[dev]"
uv run pytest -q # the whole suite, standalone
uv run artifactforge scorecard # every gate, and what it measured
```
EvidenceForge 是可选的,且仅用于 CI。请注意,尽管它作为 `evidenceforge` 导入,但其**发行版名称**为 `evidence-forge`:
```
uv pip install "evidence-forge @ git+https://github.com/Cisco-Talos/EvidenceForge@v1.13.1"
uv run python -m evidenceforge generate scenario.yaml -o ef-out
ARTIFACTFORGE_EF_OUT=ef-out uv run pytest -q tests/ef_contract/
```
## 在真实数据上的表现
在 EvidenceForge v1.13.1 版本附带的 `branch-office-example` 场景中,通过配套适配器读取:**7 台主机,446 条带哈希的 Sysmon 记录,446 条已还原并验证**(与上游实际发出的摘要进行比对),解析为 93 个不同的逻辑二进制文件,并测试了上游的两种种子形式。
`tests/ef_contract/test_golden_formulas.py` 会调用 EvidenceForge 自身的 `_generate_hashes`,并要求我们的转录与其完全一致,因此上游私有接口的任何偏差都会在一个文件中引发报错,而不是默默地返回错误的身份。
## 它到底有多诚实?
**身份 —— 已证实。** 每个哈希形式的字段都是通过独立的解析器从磁盘上的字节重新推导出来,然后才进行比较的;40 项跨 artifact 检查中有 40 项成立,并且打破其中任何一项 —— 附加一个字节、重写 Amcache 的 `FileId`、破坏一个 quarantine UUID —— 都会让关卡 2 变红。确定性是真实的:一批数据在跨进程、哈希种子、时区和区域设置下重新生成时,字节完全一致。
**Artifact 保真度 —— 部分实现,且经过量化。** 每种格式都由两个独立实现的解析器读取,但其中两个根本不是独立的:`sqlite3` 和 `plistlib` 读写的是它们自己的格式,因此 macOS 数据库和 plist 没有受到外部检验。两者都在 `fidelity-scorecard.json` 中被声明为缺口 —— 这是测量设备的局限性,而不是被测对象的失败,这就是为什么它们不决定最终结论的原因。(由于下文的关卡 4,目前结论显示为 `fail`。)除此之外,每种格式都有其真实的局限性,[`KNOWN_TELLS.md`](KNOWN_TELLS.md) 列出了这些:只有 ASCII 键名的最小化注册表 hive、未压缩的 prefetch(而 Windows 10 会对齐压缩)、使用了比任何当前 clang 发出的版本都要旧的链接器习惯用法的 Mach-O。
**基准有效性 —— 目前未通过,且数据已公开。** 关卡 4 为**红色**。参考求解器得了 100% 的分数,而一个什么都不懂的求解器也能拿到 100%:对于每个候选者,计算有多少其他文件提到了它的名字,然后取最大值。在一个保留测试套件上测量:
| | |
|---|---|
| 参考求解器(真实解析器,真实连接) | **100%** |
| `footprint` 对抗者(计算子字符串出现次数,不进行解析) | **72.7%** |
| 随机基准底线(在可见候选者中猜测) | **4.2%** |
这三个数字就是 `fidelity-scorecard.json` 中的数字,是在一个保留测试套件上以 `--n 40` 测得的。使用 `artifactforge scorecard --n 40` 重现它们。底线是蒙特卡洛估计值,会随 `n` 略有波动,因此提交的记分卡是记录在案的数据 —— 在这里引用另一次运行的数字,就是一个文档开始慢慢撒谎的方式。
本文件的一个早期版本声称*“每个对抗者得分均为 0%”*。这对于当时注册的四个对抗者来说是真实的,但对于该基准测试来说则是错误的,因为这四个对抗者全都不如五分钟的手工活儿强。上面的攻击并非偶然 —— 而是结构性的。根据定义,答案对象是注册表、Amcache、prefetch 和磁盘共同谈论的事物,而诱饵出现在其中的较少,因此计算提及次数*本身就是*在不理解其中任何内容的情况下执行预期的关联。
修复这个问题意味着删除问题而不是修补生成器:对于 `persisted_sha256`,声明的关联是“命名了一个常驻程序的那个 Run 值”,而如果在场景中平衡让诱饵被同等提及,就会导致参考求解器自身失败。问题和信息泄露其实是同一个客体。在该问题落地之前,该基准测试都是**实验性**的,不应报告从中得出的任何分数。生成器以及关卡 1 到 3 不受影响。
**它不是什么。** 不是磁盘镜像,不是内存,不是 EVTX,不是活动主机。它的层级是响应者工具直接读取的松散文件,且它不是威胁情报。
## 状态
处于早期实验阶段,版本 0.0.1,未在 PyPI 上发布任何内容。**关卡 1 到 3 通过;关卡 4 为红色,其数据如上所示。** 此外还剩下两个已声明的缺口。位于仓库根目录下的 `fidelity-scorecard.json` 是诚实的记录 —— 它发布它实际读取的任何内容,目前其中包含了一项失败。采用 MIT 许可证是刻意为之,因此如果哪天觉得有用,它的任何部分都可以毫无障碍地被合并到上游。
请参阅 [`docs/DESIGN.md`](docs/DESIGN.md) 了解架构和关卡准则,[`docs/ROADMAP.md`](docs/ROADMAP.md) 了解尚未构建的内容,以及 [`integration/evidenceforge/`](integration/evidenceforge/) 了解上游贡献将涉及哪些内容的草案 —— 该草案尚未向任何人提出。
标签:仿真数据生成, 安全测试, 安全规则引擎, 攻击性安全, 数字取证, 自动化脚本, 逆向工具