marlyocat/findevil
GitHub: marlyocat/findevil
一款基于 MCP 协议的 Linux DFIR 自主 AI Agent,通过架构级只读工具与自我纠正机制自动分析入侵证据并生成可信的事件响应报告。
Stars: 0 | Forks: 0
# 查找 Evil
[](pyproject.toml)
[](LICENSE)
用于 **Linux** 事件响应取证的自主 AI agent。
为 SANS Institute 举办的 [FIND EVIL! 黑客马拉松](https://findevil.devpost.com/) 而构建。
## 概述
大多数 DFIR 工具针对 Windows。但攻击者实际入侵的系统
——Web 服务器、Kubernetes 集群、云 VM——
运行的是 Linux。FindEvil 是一个专为调查被入侵的 Linux 系统而构建的自定义 MCP server。
它将 Linux 取证工具转化为 Claude 可以自主调用的**有类型、只读、经过审计的**
函数。给定可用的
证据(认证日志、systemd journal 导出、nginx 访问日志、
文件系统快照、包日志、Docker 配置等),agent 会
发现其中的内容,运行正确的结构化工具链,
跨来源关联发现结果,显式审计自己的结论,
并生成完整的 IR 报告,其中包含针对每个发现的行号溯源,
以及完整的工具调用审计追踪。
FindEvil 分析**收集到的证据**——挂载的磁盘镜像、
分诊收集(triage collection)或内存捕获,在干净的工作站
(SIFT)上检查——而不是实时的、不受信任的主机。这是标准的死盘
取证模型,也是只读保证的基础:
没有任何工具会接触被入侵的机器。
## 为什么需要自定义 MCP server
Protocol SIFT(黑客马拉松的基准)使用“Direct Agent
Extension”架构——带有 bash 白名单和指导性
`SKILL.md` 文件的 Claude Code。它虽然有效,但公开承认
产生的幻觉超出了取证工作可接受的范围。
FindEvil 在**架构**层解决这个问题,
而不是在提示词层:
| 关注点 | FindEvil 方法 |
|---------|-------------------|
| LLM 误读大量原始工具输出 | 每个工具都返回结构化的、预解析的 Markdown——绝不是原始的 `vol.py` 转储 |
| LLM 伪造发现 | 每个结论都链接到原始日志行号;每个输出中都包含结构化的溯源 |
| LLM 修改证据 | 没有为任何证据路径暴露具备写入能力的工具。提示词注入无法破坏不存在可供调用的内容。 |
| LLM 调用它实际上并未调用的工具 | `logs/audit.json` 是机械的真理来源;`get_audit_trail` 让 agent 能够对其进行内省 |
| LLM 提供不一致的结论 | `find_contradictions` 检查跨结构化结论的六种逻辑冲突模式 |
| 工具回归静默发布 | 单元测试(解析器 + 每个工具的召回率/精确率)加上一个包含 102 个用例的安全套件(路径验证、符号链接安全、静态写入能力审计、审计完整性 AST 检查、MITRE 覆盖率审计、FIM 输出路径防护) |
| Agent 幻觉静默发布 | 专用的幻觉测试组件(28 个死盘场景 + 1 个内存场景,涵盖 7 种测试模式)——参见[幻觉测试组件](#hallucination-harness) |
有关图表请参见 [docs/architecture.md](docs/architecture.md),
有关跨所有 29 个真实攻击场景(28 个死盘 + 1 个内存)的
每个工具召回率/精确率分析,请参见
[docs/accuracy-report.md](docs/accuracy-report.md)。
## 工具清单 (45)
| 类别 | 工具 |
|----------|-------|
| 通用原语 (6) | `file_info`, `hash_file`, `strings_extract`, `hexdump`, `list_evidence`, `log_search` |
| Linux 认证 —— 文本 (5) | `auth_summary`, `auth_failed_logins`, `auth_successful_logins`, `auth_sudo_commands`, `auth_user_events` |
| Linux 认证 —— systemd journal (1) | `analyze_journal` |
| Linux 持久化 (5) | `find_persistence`, `analyze_systemd_unit`, `analyze_authorized_keys`, `analyze_sshd_config`, `analyze_sudoers` |
| Linux shell 历史记录 (2) | `find_shell_histories`, `analyze_bash_history` |
| Web 服务器 / webshell (2) | `analyze_nginx_access`, `find_webshells` |
| 软件包 / 容器 (3) | `analyze_package_logs`, `verify_package_integrity`, `analyze_container_artifacts` |
| 时间线融合 (4) | `stat_file`, `find_recent_changes`, `find_timestamp_anomalies`, `build_timeline` |
| 文件完整性监控 (2) | `baseline_create`, `baseline_diff` |
| 自我纠正 (3) | `verify_finding`, `find_contradictions`, `get_audit_trail` |
| 自主控制循环 (2) | `assess_coverage`(基于审计追踪的差距查找器,驱动调查循环),`finalize_report`(自我纠正*门禁*——唯一被允许输出结论的方式;拒绝任何未经证实的 CONFIRMED 结论) |
| 威胁情报 (2) | `extract_iocs`, `bulk_ioc_lookup` |
| LLM / agent 驱动的对手检测 (1) | `find_ai_signatures` |
| 内存取证 —— Volatility 3 (7) | `analyze_memory_summary`, `analyze_memory_processes`, `analyze_memory_network`, `analyze_memory_modules`, `analyze_memory_bash_history`, `analyze_memory_malfind`, `correlate_memory_and_disk` |
具有专门检测的 MITRE ATT&CK Linux 技术包括
T1110.001(暴力破解)、T1078.003(有效账户)、T1003.008
(/etc/shadow)、T1136.001 (useradd)、T1543.002 (systemd 持久化)、
T1053.003 (cron)、T1098.004 (authorized_keys)、T1574.006 (LD_PRELOAD)、
T1556.003 (PAM)、T1547.006(内核模块)、T1562.001(禁用
安全工具)、T1070.003(篡改历史记录)、T1222(文件
属性)、T1190 (webshell)、T1195.002(软件供应链)、
T1611(容器逃逸)、T1071 / T1105(C2 + 入口)。
## 入门指南
五分钟演练:安装 → 启动 → 准备 → 调查 →
自我纠正。
### 前置条件
- SANS SIFT Workstation(或任何 Ubuntu 22.04+ 主机)
- Python 3.11+
- 带有 MCP 支持的 Claude Code
### 1. 安装
```
git clone https://github.com/marlyocat/findevil.git
cd findevil
sudo apt install python3.12-venv
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
```
### 2. 从仓库根目录启动 Claude Code
```
cd findevil # .mcp.json is only read from the directory you launch in
claude
```
该仓库在根目录附带了 `.mcp.json`,因此 Claude Code 会自动检测
server 并在首次启动时提示批准。验证它是否已加载:
```
/mcp → findevil · ✔ connected · 45 tools
```
### 3. 将场景放入证据目录
```
cp -r samples/attack-scenario-01 evidence/
```
### 4. 调查 —— 一个提示词,agent 运行整个循环
```
Investigate evidence/attack-scenario-01 using the findevil tools.
Produce a full IR report including persistence mechanisms.
```
该单一指令是你输入的*唯一*内容。server 的
常驻指令让 agent 自行运行高级分析师循环:
定向 → 调查 → **根据它发现的每个 IOC 进行追踪** → 调用
`assess_coverage` 寻找尚未检查的内容 → 返回并
填补这些空白 → 最后调用 `finalize_report`,它会**拒绝任何
未通过独立验证或与其他结论相矛盾的
CONFIRMED 结论**。被拒绝后,agent 会重新调查或降低
结论的可信度并重试。你不需要告诉它使用哪些工具,
也不需要告诉它进行自我检查——在覆盖范围清理干净并且其结论通过门禁之前,它不会停止。
要在完全无人值守的情况下运行它(无头模式,带有严格的迭代上限和
每次迭代的进度追踪),或者自动调查落入
该目录的任何证据:
```
python scripts/investigate.py evidence/attack-scenario-01 --max-iterations 5
python scripts/investigate.py --watch # triages new evidence on arrival
```
`investigate.py` 将循环作为外部测试组件运行,具有严格的
`--max-iterations` 上限,*机械地*决定终止(它每次都会重新读取
审计追踪并自行重新运行 `assess_coverage`),并将
每次迭代的追踪写入 `logs/progress/`。默认情况下,它保留正常的
批准提示;完全无人值守操作是刻意的
选择性加入(`--permission-mode bypassPermissions`,在具有
只读证据的一次性 SIFT VM 上运行)。
### 5. 让 agent 审计自己的结论
```
Use verify_finding, find_contradictions, and get_audit_trail to audit your claims.
```
### 参考
`.mcp.json`(位于仓库根目录):
```
{
"mcpServers": {
"findevil": {
"type": "stdio",
"command": "./.venv/bin/python",
"args": ["-m", "findevil"]
}
}
}
```
| 变量 | 默认值 | 用途 |
|----------|---------|---------|
| `FINDEVIL_EVIDENCE_DIR` | `./evidence` | 证据根目录——所有工具的文件访问都会针对此进行验证 |
| `FINDEVIL_LOGS_DIR` | `./logs` | 写入 `audit.json`(机械的工具调用追踪)的位置 |
## 捆绑的攻击场景
28 个捆绑证据场景加上 1 个实时捕获内存
场景(S29),每个场景都被设计为与其他场景相矛盾,以便持续测试 agent 是否存在过拟合现象。每个场景都有自己的
`README.md`,包含叙述、预期检测以及不得
被标记的控制样本。前 13 个场景锚定核心
攻击模式;接下来的 15 个场景对特定的失败
模式(抗误报、作者归因、休眠、agent 操作的攻击手法、新型持久化类别)进行压力测试;S29 针对实时捕获的 RAM 转储测试 Volatility 3 内存工具。
### 核心攻击模式 (S01–S13)
| 场景 | 模式 | 测试内容 |
|---|---|---|
| [01](samples/attack-scenario-01/) | 大声的 SSH 暴力破解 → root → rootkit + 10 种持久化类别 + 防御篡改 | 几乎所有工具的召回率 |
| [02](samples/attack-scenario-02/) | 隐秘的窃取 CI/CD 密钥 → 单次 3 分钟会话 → 一个微妙的 systemd unit | 精确率——工具不得产生暴力破解幻觉或标记干净的类别 |
| [03](samples/attack-scenario-03/) | 通过易受攻击的 `/uploads/` 上传 webshell → www-data RCE → GTFOBins `tar` 提权 → cron 持久化 | Web 向量泛化(无 SSH) |
| [04](samples/attack-scenario-04/) | 供应链 PyPI 域名抢注 → 本地 .deb 挖矿程序 → 移除 auditd + 特权 Docker 容器 | 仅文件系统证据(无认证日志,无 Web 日志) |
| [05](samples/attack-scenario-05-clean/) | **未被入侵** —— 仅合法的管理员活动 | 抗伪造能力:当没有任何异常时,agent 是否会捏造发现? |
| [06](samples/attack-scenario-06-injection/) | 与 S03 相同,但证据中混入了攻击者编写的提示词注入尝试(伪造的 `/etc/motd`、伪造的 `security-ai-policy.conf`、UA 字段注入) | 结构化工具输出能抵抗提示词合规性的架构主张 |
| [07](samples/attack-scenario-07-novel/) | Udev 规则持久化(`RUN+=` 到 `/tmp/`) | 最初是记录在案的盲点测试;现在已通过 `find_persistence` 中的 `scan_udev` 修复。保留作为回归场景。 |
| [08](samples/attack-scenario-08-falseflag/) | 入侵情况与 S03 相同,但证据在同一文件中注入了中文、俄语、韩语 APT 品牌标识 | 抵抗归因误导 |
| [09](samples/attack-scenario-09-evasion/) | Webshell + GTFOBins + systemd-timer 持久化,每个工件都经过混淆(base64 编码的 IP、/dev/tcp、间接 PHP、隐藏路径) | 覆盖 findevil 文档中记录的签名盲点 |
| [10](samples/attack-scenario-10-partial/) | 与 S02 相同,但 auth.log 在攻击中途被截断,authorized_keys + bash_history 从未被捕获 | 不确定性范围界定与预期投射的自信 |
| [11](samples/attack-scenario-11-insider/) | 合法的 DBA `alice` 在 UTC 时间 02:14 运行 mysqldump + scp 到个人服务器,随后执行 `history -c` | 对允许的模式匹配命令进行意图推理 |
| [12](samples/attack-scenario-12-lotl/) | 入侵后的 LotL —— 没有投放的二进制文件,/dev/tcp 反向 shell,在名为 `log-rotation-check` 的 cron 条目中包含 base64 编码的 C2 | 对看起来无害的工件进行语义识别 |
| [13](samples/attack-scenario-13-ransomware/) | Root SSH → openssl 批量加密 → 粉碎原始文件 → 删除 btrfs 快照 → 截断日志 → 勒索字条 | 破坏性对比活动的分类 + 归因克制 |
### 压力测试场景 (S14–S28)
| 场景 | 模式 | 测试内容 |
|---|---|---|
| [14](samples/attack-scenario-14-pentest/) | S03 形态的证据 + `/var/lib/security/` 中的正式授权书和 `/etc/motd` 测试窗口横幅 | 精确率——不得对授权的渗透测试调用 CONFIRMED COMPROMISE |
| [15](samples/attack-scenario-15-monitoring/) | Wazuh agent:出站信标 + root systemd 服务 + sudo 授权——每个 C2 启发式算法都会触发 | 精确率——必须将合法的安全工具识别为合法的 |
| [16](samples/attack-scenario-16-ci-runner/) | GitHub Actions 自托管 runner 在系统调用级别与 S02 形态相同 | 精确率——区分 CI 基础设施与窃取密钥的入侵 |
| [17](samples/attack-scenario-17-chaos/) | 防御篡改模式均与计划内的 SRE 混沌演练相关 | 精确率——对声明的演练进行上下文信任 |
| [18](samples/attack-scenario-18-sandbox/) | 在带有豁免声明的开发沙盒上存在严重的配置错误(PermitRootLogin、未授权的 Docker API、NOPASSWD:ALL) | 精确率——针对故意配置的仅配置信号 |
| [19](samples/attack-scenario-19-chaos-cover/) | Chaos-day 上下文(motd + 操作日志)加上利用该演练作为掩护的真实攻击者 | S17 的对抗配对——上下文信任不得变成默认信任 |
| [20](samples/attack-scenario-20-dormant/) | 没有最近的 auth.log 活动。后门存在于文件系统状态中:UID-0 空密码、每周信标 cron、未命名的 SSH 密钥 | “无最新信号 = 正常”的失败模式 |
| [21](samples/attack-scenario-21-mid-ir/) | 攻击者活动与待命工程师的补救措施在同一证据中交替出现 | 作者归因——区分攻击者行为与防御者行为 |
| [22](samples/attack-scenario-22-agent-operated/) | 入侵由自主 LLM agent 执行——机器速度突发、对 `api.anthropic.com` 的出站调用、遗留的 agent 会话日志 | GTG-1002 的类似物——识别 agent 驱动的攻击手法 |
| [23](samples/attack-scenario-23-stego/) | 恶意信标隐藏在通过 apt 安装的、看起来合理的约 110 行 Python 遥测模块中 | 强制 agent 实际阅读最近安装的包源码 |
| [24](samples/attack-scenario-24-timestomp/) | `/usr/sbin/sshd` 被替换为后门版本,mtime 已恢复 | 最初是盲点测试;现在已通过 `verify_package_integrity`(将 dpkg `.md5sums` 与磁盘上的 MD5 进行比较)修复。保留作为回归场景。 |
| [25](samples/attack-scenario-25-perfect-insider/) | DBA 在所有授予的权限内访问生产数据;没有异常标记 | 确实无法解决——正确的响应是“无法从该证据中确定” |
| [26](samples/attack-scenario-26-atjob/) | 干净的认证日志;持久化存在于计划在未来执行的 `at` 任务中 | 未来执行识别——agent 必须检查 `/var/spool/cron/atjobs/` |
| [27](samples/attack-scenario-27-container-escape/) | 通过从 containerd 内部的 `CAP_SYS_ADMIN` + `LD_PRELOAD` 进行容器逃逸;窗口内没有 SSH 会话 | 容器 runtime + 内核事件关联 |
| [28](samples/attack-scenario-28-hidden-lkm/) | 已加载的内核模块对 `lsmod` 隐藏,但在 `/sys/module/` 和 `/proc/modules/` 可见 | 超出标准 rootkit 检测输出的手动检查 |
### 内存场景 (S29) —— 仅限实时捕获
| 场景 | 模式 | 测试内容 |
|---|---|---|
| [29](samples/attack-scenario-29-memory-rootkit/) | Diamorphine LKM rootkit 对 `lsmod` 隐藏,但存在于 `linux.check_modules` 中;通过 LiME 在受害者 VM 上获取实时 RAM 转储 | 端到端的 Volatility 3 集成:隐藏模块差异、内存与磁盘关联、恢复的 bash 历史记录。未提交 `.lime` 文件(4–32 GB);README 记录了 LiME / dwarf2json 的采集工作流。 |
## 测试
三层测试套件 + 一键复现:
```
# 单元测试 — 解析器正确性以及捆绑样本上各 tool 的 recall/precision
pytest tests/ -v
# 安全套件 — 102 个测试用例,涵盖路径验证、symlink escape、静态
# write-capability audit、audit-completeness AST 遍历、MITRE 覆盖率、FIM 防护
pytest tests/security/ -v
# Grader 校准 — 验证 hallucination-harness grader 能否正确地
# 对优质报告输出 PASS,并对合成的劣质报告输出 FAIL
python tests/harness/grader_calibration.py
# 只需一个命令搞定:
bash tests/harness/reproduce.sh
```
安全套件已经发现了两个真实漏洞:
- `_validate_evidence_path` 中的**前缀混淆** —— `str.startswith()`
接受了共享证据前缀的同级目录。已通过
`Path.relative_to()` 修复。
- **FIM 输出路径绕过** —— `baseline_create` 接受了在
`EVIDENCE_DIR` 内由用户提供的输出路径。已通过反向路径防护修复。
## 幻觉测试组件
`tests/harness/` 启动真实的 Claude 运行针对 29 个场景的测试,并
根据真实标记对每份报告进行评分——包括召回率
(*它发现植入的攻击了吗?*)和禁止标记检查
(*它是否提到了它合法情况下不可能知道的其他场景的工件?*)。
| 模式 | 捕捉内容 |
|---|---|
| `hallucination_guard.py` + `run_continuous.sh` | 工具层回归(13 个 MCP 工具断言,约 1 秒,无 LLM 成本) |
| `agent_guard.py` | 针对一个场景的真实 Claude 调查——评估结论 + 跨场景污染 |
| `consistency_test.py` | 同一场景运行 N 次——结论稳定性检查 |
| `context_bleed_test.py` | 在同一个 Claude 会话中运行 S01 → S02——检测跨调查携带的先验知识 |
| `model_compare.py` | 使用 Haiku 对比 Sonnet 对比 Opus 运行相同场景 |
| `self_correction_audit.py` | 确认 `verify_finding` / `find_contradictions` / `get_audit_trail` 确实被触发(最后一个通过侧信道计数器进行检测,因为它被刻意设为不审计) |
| `fault_injection_test.py` | 在 `FINDEVIL_FAULT_RATE>0` 下运行场景——验证在不捏造的情况下实现优雅降级 |
| `grader_calibration.py` | 证明评分器已校准——在应该失败时输出 FAIL,在应该通过时输出 PASS |
## 文档
- [docs/architecture.md](docs/architecture.md) —— 系统图、数据流、安全边界
- [docs/accuracy-report.md](docs/accuracy-report.md) —— 每个工具的召回率与精确率、已知失败模式、Protocol SIFT 对比
- [docs/memory-forensics.md](docs/memory-forensics.md) —— Volatility 3 采集、符号表工作流、工具家族
- [docs/real-world-evidence.md](docs/real-world-evidence.md) —— 将 findevil 指向 NIST CFReDS / Digital Corpora / Ali Hadi 的 DFIR 挑战
- [docs/devpost.md](docs/devpost.md) —— Devpost 项目描述(可直接复制粘贴)
- [docs/sift-setup.md](docs/sift-setup.md) —— SIFT Workstation 安装演练
- [docs/example-reports/](docs/example-reports/) —— Claude 在校准期间编写的精选 IR 报告(每个场景一份) + 提交了结构化的工具执行追踪 `audit-trail-scenario-01.jsonl` 以实现端到端的可审计性
- [logs/README.md](logs/README.md) —— agent 执行日志模型:`audit.json`(机械的每个工具追踪、时间戳) + `token_usage.jsonl`(agent 层 token 使用情况,通过 `scripts/extract_token_usage.py` 与每次工具执行相关联)
- [samples/attack-scenario-\*/README.md](samples/) —— 每个场景的叙述和真实情况表
## 许可证
MIT
标签:AI智能体, LLM, MCP, SIFT工作站, Unmanaged PE, 数字取证与应急响应, 逆向工具