M-Abrisham/find-evil-hackathon
GitHub: M-Abrisham/find-evil-hackathon
一个面向DFIR agent的评估驱动优化循环框架,通过确定性评分和自动回退机制在SANS SIFT Workstation上持续改进取证分析agent的准确性。
Stars: 0 | Forks: 0
# Protocol SIFT — DFIR Agent 的评估驱动优化循环
[](https://www.sans.org/)
[](LICENSE)
**SANS "Find Evil!" 黑客松参赛作品。** 采用 [MIT License](LICENSE) 授权。
## 它是什么
交付物是一个**评估驱动的优化循环**,而不是一个取证 agent。遵循 Hamel Husain 的评估方法论(*评估 → 调试 → 修改*;“查看你的数据”;在验证之前保持 AI Judge 关闭),该循环根据带有已知标准答案的案例对 DFIR agent 进行评分,然后根据评分信号改进 agent 的**上下文 artifact** —— 即其 `CLAUDE.md` 合约和五个取证 `SKILL.md` 文件 —— 全过程**无需重新训练模型**。
它所评分的 agent 是 **Protocol SIFT** = Claude(`claude -p`, Opus)加上 [`protocol-sift/`](protocol-sift/) 配置层,在 SANS SIFT Workstation 上运行。Protocol SIFT 是**被测系统 (SUT)** —— 它是证明该循环有效的证据,而不是贡献本身。贯穿始终的核心规则是:**优化器提议;确定性评估器裁决。** 只有当 LLM 无法影响的指标表明 agent 变得更好且没有回归时,修改才会被保留 —— 否则它会自动回退,并且每一圈都会被写入防篡改账本。
## 如何满足要求
黑客松要求的三项能力都映射到了本仓库中的具体机制:
| 所需能力 | 实现方式 | 所在位置 |
| --- | --- | --- |
| **自我修正** | 该循环诊断失败的根本原因,修改*一个* artifact,并且只有在综合得分上升且没有回归的情况下才保留它 —— 否则自动回退。在实践中,它捕获了一个错误的标准答案和一个受污染的对照组,并且 agent 清除了无辜的姓名 / 在证据不足时限制了归属。 | [`eval/diagnosis/`](eval/diagnosis/), [`scoring/keep_or_revert.py`](scoring/keep_or_revert.py), [`scoring/run_loop.py`](scoring/run_loop.py), [`scoring/score_ledger.py`](scoring/score_ledger.py) |
| **准确性验证** | 一个**不可钻空子**的指标:*可发现召回率*只有在 IOC 的值出现在 agent 实际看到的证据中时才给予认可,并配有一个*伪造计数器* —— 在结构上无法奖励幻觉。每一个发现都可以追溯到产生它的工具。 | [`scoring/scorer.py`](scoring/scorer.py) (52 个测试), [`eval/score.py`](eval/score.py), [`trace_enrich/provenance.py`](trace_enrich/provenance.py) |
| **分析推理** | Agent 输出结构化的调查叙述(结论 + IOC 列表 + MITRE ATT&CK),而不是原始日志;确定性断言评分器会对架构/完整性和技能指令遵循度进行评分。 | [`protocol-sift/global/CLAUDE.md`](protocol-sift/global/CLAUDE.md), [`scorers/`](scorers/) (a1–a8, s1–s8) |
## 架构
该系统由两层加上一个提议/裁决门组成:**Layer 0** 是 Protocol SIFT(SUT);**评估循环**(Layer 1+2 + 门)是核心贡献。几乎整个循环都是确定性代码 —— 信任路径中*唯一*的 LLM 是受大小限制的 Rewriter,而 Judge 严格保持 advisory(参考性质)。
```
flowchart TB
subgraph HUMAN["HUMAN-IN-THE-LOOP — set once, then hands-off (Hamel gates · define 'good')"]
direction LR
H1["H1 · Lock answer keys"]
H2["H2 · Validate the metric
(0 scorer disagreements)"] H3["H3 · Validate the judge
vs human labels"] H4["H4 · Lock held-out case
BEFORE optimizing"] end subgraph L0["LAYER 0 · SYSTEM UNDER TEST — Protocol SIFT (the DFIR agent; the loop tunes its artifacts)"] direction LR AGENT["Agent — Claude Code (claude -p, Opus)
+ CLAUDE.md contract
+ 5 forensic SKILL.md
(memory · plaso · sleuthkit · windows · yara)"] MCP["MCP tool bridge"] TOOLS["SIFT DFIR tools
Volatility · Sleuth Kit · plaso · tshark · YARA"] EVID[("READ-ONLY evidence
E01 · memory · pcap")] OUT["Output pipeline
verdict + IOC list + MITRE ATT&CK"] AGENT --> MCP --> TOOLS --> EVID AGENT --> OUT end subgraph LOOP["★ THE EVAL LOOP — the hackathon contribution (grades + self-improves Protocol SIFT)"] direction TB subgraph L1["LAYER 1 · EVALUATOR — DETERMINISTIC · the source of truth (plain code, no LLM)"] direction LR RUN["Case Runner
parity gate (fail-closed) -> claude -p"] PARSE["Trace Parser
+ tool->skill Attributor"] SCORE["DETERMINISTIC Scorer
verdict · MITRE · findable-recall · fabrications"] JUDGE["LLM Judge
(ADVISORY ONLY)"] CLUST["Error Clusterer
(rank worst failure)"] RUN --> PARSE --> SCORE --> CLUST SCORE -. "advisory — never changes the score" .-> JUDGE JUDGE -. advisory .-> CLUST end GATE{{"PROPOSE / DISPOSE GATE
keep edit IFF composite non-regresses
(recall up · fabrications=0 · verdicts up · MITRE up; tie = REVERT)
else auto-revert — a score the LLM cannot fake"}} subgraph L2["LAYER 2 · OPTIMIZER — adaptive (only the Rewriter is an LLM call)"] direction LR BLAME["Skill Blamer
map failure -> owning artifact
via tool->skill registry"] REWRITE["Rewriter — the ONE LLM call
size-capped; cannot touch scorer or keys"] RERUN["Re-Run through Layer 1"] ORCH["Loop Orchestrator
a script, not an LLM
owns keep/revert + ledger"] REGGATE["Held-out Regression Gate
(anti-overfit)"] COMMIT["COMMIT"] BLAME --> REWRITE --> RERUN --> ORCH --> REGGATE --> COMMIT end end subgraph AUDIT["AUDIT TRAIL — records, never decides"] direction LR BT["Braintrust spans
(OpenTelemetry)"] PROV["IOC -> source provenance"] LEDGER["Immutable score ledger
hash-chained · tokens + timestamps per lap"] end HUMAN -. "defines good" .-> L1 H4 -. locks .-> REGGATE AGENT --> RUN EVID -. read-only .-> RUN CLUST -- "worst failure" --> BLAME REWRITE -- "edits ONE artifact" --> AGENT SCORE == "deterministic reward" ==> GATE RERUN == "new score" ==> GATE GATE == "keep / revert" ==> ORCH REGGATE -. "rollback on regress" .-> AGENT RUN -.-> BT PARSE -.-> PROV SCORE -.-> LEDGER ORCH -.-> LEDGER classDef det fill:#e8f4ea,stroke:#2e7d32,color:#1b3a20; classDef llm fill:#fdecf0,stroke:#b35a00,color:#5a2e00; classDef gate fill:#fff4cc,stroke:#b8860b,stroke-width:3px,color:#5a4500; classDef human fill:#e7eefc,stroke:#34548a,color:#1f2f5a; classDef sut fill:#f0f0f3,stroke:#555,color:#222; classDef audit fill:#f3eef7,stroke:#6a4a8a,color:#34204a; class RUN,PARSE,SCORE,CLUST,BLAME,RERUN,ORCH,REGGATE,COMMIT det; class JUDGE,REWRITE llm; class GATE gate; class H1,H2,H3,H4 human; class AGENT,MCP,TOOLS,EVID,OUT sut; class BT,PROV,LEDGER audit; ``` **核心要点:** 信任路径是确定性代码(绿色)。其中唯一的 LLM 是 **Rewriter**(对一个 artifact 进行一次受大小限制的修改),而 **Judge** 严格保持 advisory —— 它永远不会改变得分。只有当 LLM 无法影响的数值表明有所改进时,修改才会被保留;否则它会自动回退。正是这种边界使得系统能够保持自主性,而不会学会伪造自己的成功。 完整的架构说明 —— 组件细节、单圈数据流演练以及安全边界 —— 位于 [`ARCHITECTURE.md`](ARCHITECTURE.md) 中。 ## 仓库布局 | 路径 | 角色 | | --- | --- | | [`protocol-sift/`](protocol-sift/) | **被测系统 (SUT):** DFIR agent 配置层 —— `global/CLAUDE.md` 合约、5 个取证 `skills/*/SKILL.md` 以及交付合约 (`contract/`)。 | | [`eval/`](eval/) | **盲测评估框架**(核心交付物):`run_blind.py`(在封闭沙箱中进行原始 vs SIFT 对比)、`score.py`(包含 `--judge` 门控)、`parity_check.py`(失败即止的 parity gate)、schema。 | | [`eval/diagnosis/`](eval/diagnosis/) | **6 个规则变更“诊断协议”工具:** 失败聚合 + Wilson CI + z-test、Judge 验证 (TPR/TNR)、单 artifact 消融测试、单调回归门控、构建时 key 验证器、合约↔评分器偏差阻断。 | | [`contract-build/`](contract-build/) | 渲染交付合约 + 按条款的评分器 (`scorer.py`, `presence_scorer.py`)。 | | [`scoring/`](scoring/) | **优化循环机制:** 确定性 IOC/结论/MITRE 评分器(52 个测试)、composite gate、保留或回退决策器、哈希链得分账本、单圈编排器、冻结的 MITRE ATT&CK id 目录生成器。 | | [`scorers/`](scorers/) | 确定性断言评分器 `a1`–`a8`(架构/完整性)+ `s1`–`s8`(技能指令遵循度)。 | | [`harness/`](harness/) | `run_case.py`(驱动 `claude -p --output-format stream-json`)+ `parse_stream.py`。 | | [`trace_enrich/`](trace_enrich/) | 运行后的 Braintrust OpenTelemetry 技能→工具归因 + 溯源。 | | [`dataset/`](dataset/) | `cases.jsonl`、证据清单、manifest、哈希值、标准答案黑名单、案例验证器。 | | [`playbooks/`](playbooks/) | 24 个主题的 DFIR playbook 库 + 生成器工厂 + 黄金 playbooks。 | | [`scripts/`](scripts/) | 经红队强化的 secret/answer-key `leak_scan.py` + 其测试 + 红队测试集。 | | [`docs/`](docs/) | `ACCESS.md`、`DATASET.md`、`ASSERTION_CATALOG.md`、`PLAN.md`。 | ## 设置与运行方法 ### 前置条件 - 一台 **SANS SIFT Workstation**(agent 将调用其中的取证工具运行)。 - **Claude Code** (`claude -p`, Opus) —— agent 运行时。 - **Python 3** —— 评分器、门控和循环机制仅使用标准库。 - **Braintrust SDK** —— *可选*,仅在需要进行 OpenTelemetry 追踪捕获/增强时使用。 ### 配置 secrets 复制示例 env 文件并填入你自己的 key。**永远不要提交真实的 key** —— 泄漏扫描门控正是为了阻止这种情况而存在的。 ``` cp .env.example .env # 然后编辑 .env 并设置: # BRAINTRUST_API_KEY= # 可选;仅用于 trace 捕获
# (trace_enrich/ helper 会从 $BT_API_KEY 读取同一个 key — 参见 docs/EXECUTION-LOGS.md)
```
### 核心 make 目标
```
make sync # rsync the repo to the SIFT Workstation VM
make eval # run the Braintrust eval on the VM
make test # run all unittest suites (scoring/, trace_enrich/, scorers)
make validate # validate the dataset cases
make leak-scan # secret/answer-key leak gate over the staged changeset (run before EVERY commit)
make leak-scan-test # the scanner's own unit tests + red-team battery
make verify-ledger # verify the score-ledger hash chain
make pre-submit # leak-scan + verify-ledger (run before any public push)
```
### Judge 如何运行案例
SUT 是 **Protocol SIFT** = Claude(`claude -p`, Opus)+ SIFT Workstation 上的 [`protocol-sift/`](protocol-sift/) 配置层。要运行并对案例进行评分:
1. `make sync` 将仓库推送到 SIFT VM,然后 `make validate` 确认数据集案例格式正确。
2. 通过框架运行案例 —— [`harness/run_case.py`](harness/run_case.py) 驱动 `claude -p --output-format stream-json`;或者使用 [`eval/run_blind.py`](eval/run_blind.py) 运行 A/B 对比(在封闭的、屏蔽网络的沙箱中运行原始 Claude vs Protocol SIFT)。
3. 使用 [`eval/score.py`](eval/score.py)(确定性;`--judge` 门控是可选项,仅在验证后使用)和/或 [`scoring/scorer.py`](scoring/scorer.py) 对运行结果进行评分。
4. 检查审计追踪:追踪通过 [`trace_enrich/`](trace_enrich/) 流向 Braintrust;每个 IOC 都会映射回生成它的工具命令。
### 诊断协议框架(操作层)
这些目标驱动了 [`eval/diagnosis/`](eval/diagnosis/) 中的规则变更 / 整理协议:
```
make aggregate # per-arm failure rate + Wilson CI + 2-proportion z
make judge-validate # TPR/TNR confusion matrix gating score.py --judge
make ablate # single-artifact ablation lap
make regression # monotonic guard-case non-regression gate
make validate-keys # build-time answer-key supportability gate
make check-contract-scorer-drift # contract<->scorer drift HARD-block
make diagnosis-test # the diagnosis harness's own test suite
```
## 证据数据集
Agent 的测试对象 —— 来源、证据清单以及发现的内容 —— 记录在 [`docs/DATASET.md`](docs/DATASET.md) 中,机器可读的案例集、manifest、哈希值和验证器位于 [`dataset/`](dataset/) 中。标准答案的*值*被故意**不**予公开;一个 [`answer_key_denylist`](dataset/answer_key_denylist.txt) 以及泄漏扫描门控会将黄金 IOC 排除在这个公开仓库之外。
## 准确性与诚实
诚实比完美更受重视,因此自我评估(误报、遗漏的 artifact、幻觉产生的声明)报告在 **`ACCURACY.md`** 中。
**核心结果(在实时系统上完成的一个完整闭环):** 单次数据驱动的合约修改将**结论准确率从 0/3 提升到了 3/3**,同时保持了 **100% 的可发现召回率和 0 伪造**,且没有出现回归。该循环还足够严谨,捕获了一个**错误的标准答案**和一个**受污染的对照组**,并且 agent 在证据不足时保持保守(它洗清了无辜者的姓名,并在一个开放的、无密码的网络上限制了对人的指认,而不是直接指出罪魁祸首)。
**诚实的范围:** 这是 **n = 3 个案例**。原始 vs SIFT 的 A/B 运行结果**已捕获但尚未完全评分**(数据待定),并且在设计上,整理/保留或回退步骤中仍有真人参与。我们坦率地报告这一范围,而不是过度声称。
## 执行日志 / 审计追踪
结构化的审计追踪 —— 包含时间戳和 token 使用情况的工具执行序列、迭代追踪,以及每个发现都可追溯到生成它的工具执行 —— 记录在 **`docs/EXECUTION-LOGS.md`** 中。捕获/归因机制位于 [`trace_enrich/`](trace_enrich/) 中(Braintrust OpenTelemetry spans、技能→工具归因、IOC→来源溯源),并且每一圈的防篡改记录是 [`scoring/score_ledger.py`](scoring/score_ledger.py) 中的哈希链账本(通过 `make verify-ledger` 进行验证)。
## 演示视频
**演示视频:** *TODO — 链接待定*
## 构建于
- **SANS SIFT Workstation** —— agent 运行的取证工具环境。
- **Claude Code** (`claude -p`, **Opus**) —— 被测试的 agent 运行时。
SIFT Workstation 和 Claude Code 都是预先存在的基础。**黑客松期间构建的创新贡献是评估驱动的优化循环** —— 确定性评分器、parity gate、trace→技能归因器、blamer、提议/裁决门控、保留/回退组合决策、编排器、预留回归测试门控以及哈希链账本 —— 以及该循环产生的经过调优的 `CLAUDE.md` 合约和五个 `SKILL.md` artifact。
## 许可证
在 **MIT License** 下发布。参见 [LICENSE](LICENSE)。
(0 scorer disagreements)"] H3["H3 · Validate the judge
vs human labels"] H4["H4 · Lock held-out case
BEFORE optimizing"] end subgraph L0["LAYER 0 · SYSTEM UNDER TEST — Protocol SIFT (the DFIR agent; the loop tunes its artifacts)"] direction LR AGENT["Agent — Claude Code (claude -p, Opus)
+ CLAUDE.md contract
+ 5 forensic SKILL.md
(memory · plaso · sleuthkit · windows · yara)"] MCP["MCP tool bridge"] TOOLS["SIFT DFIR tools
Volatility · Sleuth Kit · plaso · tshark · YARA"] EVID[("READ-ONLY evidence
E01 · memory · pcap")] OUT["Output pipeline
verdict + IOC list + MITRE ATT&CK"] AGENT --> MCP --> TOOLS --> EVID AGENT --> OUT end subgraph LOOP["★ THE EVAL LOOP — the hackathon contribution (grades + self-improves Protocol SIFT)"] direction TB subgraph L1["LAYER 1 · EVALUATOR — DETERMINISTIC · the source of truth (plain code, no LLM)"] direction LR RUN["Case Runner
parity gate (fail-closed) -> claude -p"] PARSE["Trace Parser
+ tool->skill Attributor"] SCORE["DETERMINISTIC Scorer
verdict · MITRE · findable-recall · fabrications"] JUDGE["LLM Judge
(ADVISORY ONLY)"] CLUST["Error Clusterer
(rank worst failure)"] RUN --> PARSE --> SCORE --> CLUST SCORE -. "advisory — never changes the score" .-> JUDGE JUDGE -. advisory .-> CLUST end GATE{{"PROPOSE / DISPOSE GATE
keep edit IFF composite non-regresses
(recall up · fabrications=0 · verdicts up · MITRE up; tie = REVERT)
else auto-revert — a score the LLM cannot fake"}} subgraph L2["LAYER 2 · OPTIMIZER — adaptive (only the Rewriter is an LLM call)"] direction LR BLAME["Skill Blamer
map failure -> owning artifact
via tool->skill registry"] REWRITE["Rewriter — the ONE LLM call
size-capped; cannot touch scorer or keys"] RERUN["Re-Run through Layer 1"] ORCH["Loop Orchestrator
a script, not an LLM
owns keep/revert + ledger"] REGGATE["Held-out Regression Gate
(anti-overfit)"] COMMIT["COMMIT"] BLAME --> REWRITE --> RERUN --> ORCH --> REGGATE --> COMMIT end end subgraph AUDIT["AUDIT TRAIL — records, never decides"] direction LR BT["Braintrust spans
(OpenTelemetry)"] PROV["IOC -> source provenance"] LEDGER["Immutable score ledger
hash-chained · tokens + timestamps per lap"] end HUMAN -. "defines good" .-> L1 H4 -. locks .-> REGGATE AGENT --> RUN EVID -. read-only .-> RUN CLUST -- "worst failure" --> BLAME REWRITE -- "edits ONE artifact" --> AGENT SCORE == "deterministic reward" ==> GATE RERUN == "new score" ==> GATE GATE == "keep / revert" ==> ORCH REGGATE -. "rollback on regress" .-> AGENT RUN -.-> BT PARSE -.-> PROV SCORE -.-> LEDGER ORCH -.-> LEDGER classDef det fill:#e8f4ea,stroke:#2e7d32,color:#1b3a20; classDef llm fill:#fdecf0,stroke:#b35a00,color:#5a2e00; classDef gate fill:#fff4cc,stroke:#b8860b,stroke-width:3px,color:#5a4500; classDef human fill:#e7eefc,stroke:#34548a,color:#1f2f5a; classDef sut fill:#f0f0f3,stroke:#555,color:#222; classDef audit fill:#f3eef7,stroke:#6a4a8a,color:#34204a; class RUN,PARSE,SCORE,CLUST,BLAME,RERUN,ORCH,REGGATE,COMMIT det; class JUDGE,REWRITE llm; class GATE gate; class H1,H2,H3,H4 human; class AGENT,MCP,TOOLS,EVID,OUT sut; class BT,PROV,LEDGER audit; ``` **核心要点:** 信任路径是确定性代码(绿色)。其中唯一的 LLM 是 **Rewriter**(对一个 artifact 进行一次受大小限制的修改),而 **Judge** 严格保持 advisory —— 它永远不会改变得分。只有当 LLM 无法影响的数值表明有所改进时,修改才会被保留;否则它会自动回退。正是这种边界使得系统能够保持自主性,而不会学会伪造自己的成功。 完整的架构说明 —— 组件细节、单圈数据流演练以及安全边界 —— 位于 [`ARCHITECTURE.md`](ARCHITECTURE.md) 中。 ## 仓库布局 | 路径 | 角色 | | --- | --- | | [`protocol-sift/`](protocol-sift/) | **被测系统 (SUT):** DFIR agent 配置层 —— `global/CLAUDE.md` 合约、5 个取证 `skills/*/SKILL.md` 以及交付合约 (`contract/`)。 | | [`eval/`](eval/) | **盲测评估框架**(核心交付物):`run_blind.py`(在封闭沙箱中进行原始 vs SIFT 对比)、`score.py`(包含 `--judge` 门控)、`parity_check.py`(失败即止的 parity gate)、schema。 | | [`eval/diagnosis/`](eval/diagnosis/) | **6 个规则变更“诊断协议”工具:** 失败聚合 + Wilson CI + z-test、Judge 验证 (TPR/TNR)、单 artifact 消融测试、单调回归门控、构建时 key 验证器、合约↔评分器偏差阻断。 | | [`contract-build/`](contract-build/) | 渲染交付合约 + 按条款的评分器 (`scorer.py`, `presence_scorer.py`)。 | | [`scoring/`](scoring/) | **优化循环机制:** 确定性 IOC/结论/MITRE 评分器(52 个测试)、composite gate、保留或回退决策器、哈希链得分账本、单圈编排器、冻结的 MITRE ATT&CK id 目录生成器。 | | [`scorers/`](scorers/) | 确定性断言评分器 `a1`–`a8`(架构/完整性)+ `s1`–`s8`(技能指令遵循度)。 | | [`harness/`](harness/) | `run_case.py`(驱动 `claude -p --output-format stream-json`)+ `parse_stream.py`。 | | [`trace_enrich/`](trace_enrich/) | 运行后的 Braintrust OpenTelemetry 技能→工具归因 + 溯源。 | | [`dataset/`](dataset/) | `cases.jsonl`、证据清单、manifest、哈希值、标准答案黑名单、案例验证器。 | | [`playbooks/`](playbooks/) | 24 个主题的 DFIR playbook 库 + 生成器工厂 + 黄金 playbooks。 | | [`scripts/`](scripts/) | 经红队强化的 secret/answer-key `leak_scan.py` + 其测试 + 红队测试集。 | | [`docs/`](docs/) | `ACCESS.md`、`DATASET.md`、`ASSERTION_CATALOG.md`、`PLAN.md`。 | ## 设置与运行方法 ### 前置条件 - 一台 **SANS SIFT Workstation**(agent 将调用其中的取证工具运行)。 - **Claude Code** (`claude -p`, Opus) —— agent 运行时。 - **Python 3** —— 评分器、门控和循环机制仅使用标准库。 - **Braintrust SDK** —— *可选*,仅在需要进行 OpenTelemetry 追踪捕获/增强时使用。 ### 配置 secrets 复制示例 env 文件并填入你自己的 key。**永远不要提交真实的 key** —— 泄漏扫描门控正是为了阻止这种情况而存在的。 ``` cp .env.example .env # 然后编辑 .env 并设置: # BRAINTRUST_API_KEY=
标签:AI智能体, LLM评估优化, SIFT工作站, 数字取证, 用户代理, 自动化DFIR, 自动化脚本, 逆向工具