关于 dnr-respond
dnr-respond 是面向事件调查人员的响应技能,可从告警、指标、事件记录或文字报告着手。它将日志活动与源代码关联、量化影响,并生成只供审阅、不执行的响应计划。
主要功能
- 01解析告警、IOC 和事件线索
- 02按实体关联日志并构建时间线
- 03判定结果并量化影响范围
- 04从源代码分析根本原因
- 05在本地验证概念验证
- 06提出响应计划但不执行
适用场景
- 01调查安全告警或 IOC
- 02判断可疑活动是否成功
- 03统计受影响记录和用户
- 04拟定修复与检测建议
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ defending-code-reference-harness --skill dnr-respond安装后在 Claude Code 中输入/dnr-respond确认已加载。
附带文件README.md
详细介绍
dnr-respond
以线索为起点开展事件响应:从一个具体起点出发,按顺序回答事件指挥官需要了解的四个问题——**发生了什么、是否成功、影响范围有多大,以及我们该怎么处理。**输出包括判定结果、量化的影响范围、通过源码证实的根本原因,以及一份仅供提议、绝不执行的响应计划。
使用 /dnr-respond <lead> [--logs dir] [--repo path] [--fresh] 调用。
线索($1)可以是:
- 来自此次排查的
INCIDENTS.json的事件 ID(例如INC-2)——/dnr-hunt的交接结果 - 从告警队列中粘贴的告警(JSON 行或文字描述)
- IOC:IP、账户名、路由、会话标识符
- 自由文本(“客户称自己的地址出现在一封钓鱼邮件中”)
其他参数:
--logs= 日志目录或 dnr 目标目录(解析方式与/dnr-hunt相同;若targets/dnrcanary存在则为默认值,否则为当前工作目录)。--repo= 应用源码(默认为目标的app/)。--fresh= 忽略运行目录中.dnr-respond-state/里的任何检查点,并创建新的运行目录。
硬性规则(与 /dnr-hunt 共享——此工作流的约定)
- 仅凭日志证据绝不能确认存在漏洞。
confirmed_exploited必须同时具备日志证据、源码中的缺陷,以及本次会话中在本地触发的 PoC。否则最高只能判定为suspected。 - **查询,不要读取。**绝不使用
Read或cat读取日志文件;使用wc/head/tail查看概况,使用grep/awk/sort/uniq/python3进行排查。小型文件(告警队列、约 200 行以下的错误日志)可以整体读取。 - **只提议,绝不执行。**不得在任何环境(包括演示应用)中封锁、禁用、轮换或更改配置。计划中列出操作,由人工执行。
- **仅限本地。**PoC 只能针对你启动的实例,在
127.0.0.1上触发。绝不触碰远程主机。 - 每个数字都必须来自查询结果。“有多少条记录”和“有多少位客户”必须通过本次会话中运行的命令流水线得出,绝不能估算。
运行目录与检查点
首要操作 — 建立运行目录,方式与 /dnr-hunt 相同,但作为使用者。令 TARGET 为解析后的 --logs/目标路径的基本名称(默认为 targets/dnrcanary),SCOPE 为该路径。
- 线索为
INC-n(来自/dnr-hunt的交接,或你已开始响应的 hunt 中的第二条线索):将响应纳入该事件所在的调查中。{RUN}是最新的results/TARGET/<timestamp>/目录,其中包含INCIDENTS.json— 使用 Bash 查找,例如ls -1d results/TARGET/*/ | sort -r | while read d; do [ -f "$d/INCIDENTS.json" ] && echo "$d" && break; done。不要对INC-n线索调用rundir— 该目录中先前的/dnr-respond完成后,rundir会新建一个空目录,导致事件的INCIDENTS.json留在旧目录中。只有在没有运行目录包含INCIDENTS.json时(你收到的是INC-n,但从未运行过 hunt),才继续执行下面的rundir命令。 - 其他任何线索(告警、IOC、自由文本):运行 Bash 命令
python3 .claude/skills/_lib/checkpoint.py rundir results/TARGET --state .dnr-respond-state --scope "SCOPE"(若$ARGUMENTS中包含--fresh,则追加该参数)。如果目标已有运行目录,此命令会采用最新的运行目录;否则会新建results/TARGET/<timestamp>/。
该路径即为 {RUN};在下文各处替换为实际路径,并在 Bash 中为其(以及 SCOPE)加上双引号。
检查点机制与 /dnr-hunt 完全相同,状态目录为 {RUN}/.dnr-respond-state/,阶段为 0–4。当 {RUN} 中已有此前线索留下的已完成 .dnr-respond-state 时,load 会报告 complete,以下规则会将其妥善重置 — 第二条线索会丰富同一个 INCIDENTS.json,并写入自己的 RESPONSE-<lead>.md。启动时运行:python3 .claude/skills/_lib/checkpoint.py load {RUN}/.dnr-respond-state — 若状态缺失、已完成或使用了 --fresh,则执行 reset 并从阶段 0 开始;若状态为运行中且 phase_done == N,则读取 phase0.json…phaseN.json,从阶段 N+1 继续。每个阶段完成后:将负载写入 {RUN}/.dnr-respond-state/_chunk.tmp,然后运行 checkpoint.py save {RUN}/.dnr-respond-state <N> <name> --from {RUN}/.dnr-respond-state/_chunk.tmp。绝不要直接写入 progress.json;绝不要通过 heredoc/stdin 传递负载。输出完成后运行:checkpoint.py done {RUN}/.dnr-respond-state 4。
阶段 0 — 解析线索,定位输入
- 解析
--logs(dnr 目标配置或裸目录),并清点日志文件(对每个文件运行du、wc -l、head -2— 确定格式和字段位置)。预计语料已存在 — 目标 README 说明如何生成。 - 将线索解析为起始实体:
INC-n→ 从{RUN}/INCIDENTS.json(上述采用的运行目录)读取对应条目;其中的 IP、账号、路由和时间线行构成种子集。- 告警行 → 源 IP、规则、路径、时间戳。
- IOC → 实体本身。
- 自由文本 → 提取可观测信息(报告人、数据内容、时间);种子集最初可能只有路由或表名。
- 用一句话说明当前要调查的问题(例如:“203.0.113.66 针对 /login 的活动是否成功?如果没有,发生了什么?”)。阶段 1 的所有工作都应服务于该问题。
检查点 phase0.json:
{"lead": ..., "lead_type": ..., "entities": {"ips": [], "accounts": [], "routes": [], "windows": []}, "question": ..., "logs_dir": ..., "repo": ..., "files": [...]}
阶段 1 — 范围:提取实体触及的所有内容
对每个种子实体,提取其完整活动,然后向外扩展一层:
- **按 IP:**每个请求——按时间排序,包含路由、状态、大小、UA 和经过身份验证的用户。总结行为阶段,不要粘贴数百行内容。
- **按账户:**每次登录(来自哪些 IP)、每个经过身份验证的 请求。与同一语料库中该账户的历史模式进行比较——新 IP、新 UA、新流量、新时段都可能是信号。(单独一个新 IP 是基线噪声 ——用户会切换网络;在将其视为线索之前,应结合流量、频率或 会话接下来的行为进行判断。)
- **按路由:**在该时间窗口内,还有谁以相同方式访问过它?通过 告警发现的攻击者可能并非唯一的攻击者。
- **扩展一环(仅一次):**将上述发现的实体加入集合——某 IP
登录的账户、访问同一账户的第二个 IP、会话转向的路由。应有意
识地扩展一次;如果范围持续扩大,则使用
/dnr-hunt的开放式 循环工具。 - 关联所有实体的错误日志和告警队列行,整合为一条时间线。
检查点 phase1.json:
{"activity": [{"entity", "summary", "first_seen", "last_seen", "requests", "key_lines": [...]}], "expanded_entities": [...], "timeline": [...]}
阶段 2 — 判定与影响范围
用正反两方面的证据回答当前问题:
- **是否成功?**仅凭状态码无法回答——401 拦截说明未成功;带有 异常大小的 200 响应、先出错后成功的进展,以及类似数据的响应 则说明成功。陈述判定结果及具有区分力的证据。
- **量化影响范围。**访问了哪些数据:涉及哪些路由/表、多少条
记录、时间跨度多长、属于多少名不同用户/客户。每个数字都应
来自处理管道(统计外传页面大小、统计遍历的不同 ID;如果本地
有应用自身的数据,则将遍历的 ID 与所属者关联——在阶段 3 之
前尽早运行目标的确定性
seed_command也可以)。 - **检查遏制状态(只读)。**在语料库时间窗口结束时,活动是否 仍在持续,还是已经停止?攻击者最后一次操作是什么时候?
- 如果判定为“未成功”,调查仍不能就此结束——说明攻击者
试图做什么,以及失败的原因;这有助于制定计划的加固部分
和
ruled_out记录。
检查点 phase2.json:
{"verdict": ..., "succeeded": bool, "discriminators": [...], "blast_radius": {"data": ..., "records": N, "distinct_victims": N, "window": ...}, "ongoing": bool, "last_activity": ...}
阶段 3 — 根本原因与 PoC
标准与 /dnr-hunt 阶段 3–4 相同:
- 在
--repo中阅读相关处理程序;精确到文件/函数,指出漏洞 (或防御措施);检查同级路由是否存在相同漏洞类型。 - 按目标配置在本地准备种子数据并启动应用:
seed_command/app_command均以目标目录为相对路径——将目标目录设为当前 工作目录运行;通过单条命令在后台启动,并打印 PID(使用python3 -c "...subprocess.Popen..."的相同模式,参见/dnr-hunt阶段 4;如果默认端口繁忙,则设置端口覆盖环境 变量)。执行最小化 PoC,记录命令和响应摘录;针对有防御 的路由执行反向 PoC,然后运行kill <pid>(绝不能按端口或 模式终止进程)。 - 没有可运行的应用 → 判定上限为
suspected,并明确说明。
检查点 phase3.json:
{"root_cause": {"file", "function", "mechanism"}, "poc": {"command", "status", "response_excerpt"}, "negative_poc": {...}, "siblings_checked": [...]}
阶段 4 — 响应计划(拟议,绝不执行)和输出
将计划写入 {RUN}/RESPONSE.md;如果运行目录中已存在由其他负责人编写的 RESPONSE.md,则写入 {RUN}/RESPONSE-<lead>.md(例如 RESPONSE-INC-2.md);绝不静默覆盖其他事件的计划。
各部分中的每项操作都必须包含 内容 / 原因 / 判断错误时的风险:
- 结论与摘要 — 用三句话说明:发生了什么、是否成功、进展到什么程度。
- 时间线 — 阶段 1 中合并后的实体时间线。
- 遏制(拟议) — 拟封锁/拒绝的对象(IP、会话、令牌)、拟暂停的账户、拟限速或禁用的路由。每项都要列出支持该操作的证据行,以及判断错误会造成什么影响(例如,封锁 NAT IP 会让其后的合法用户无法访问)。
- 根除与修复(拟议) — 在文件/函数层面描述代码修复,并整理为与
/triage兼容的漏洞条目;如果修复需要时间,还要提出临时缓解措施。 - 恢复(拟议) — 明确要轮换哪些凭据(列出查询到的清单,而不是“所有用户”)、要通知哪些客户(使用阶段 2 中的不同受害者名单),以及需要哪些监控来确认攻击者已被清除。
- 检测工程(拟议) — 根据实际用于发现问题的线索,提出本可更早发现问题的规则:将阶段 2 中具有区分性的查询转化为告警逻辑(例如,按来源统计某路由的错误率;按顺序访问 ID 的频率;来自新 IP 的账户高频活动)。注明哪些现有告警已触发、哪些属于噪声,以及这对告警队列意味着什么。
- 待解问题 — 说明这些数据无法回答的问题(更早的历史记录、其他日志来源、被盗数据是否被用于其他地方)。
然后更新 {RUN}/INCIDENTS.json(使用与 /dnr-hunt 相同的架构;若文件不存在则创建):添加此事件或补充完善现有条目,包括结论、量化影响、根因、PoC 和时间线。可以添加其他键——评分程序会按内容匹配,而不是按结构匹配。未发现问题的结果应放入 ruled_out。
标记为已完成(checkpoint.py done {RUN}/.dnr-respond-state 4),并告知用户后续操作(将字面路径 {RUN} 替换为实际路径):
- 修复方面,在
{RUN}目录内运行:/triage INCIDENTS.json --repo <repo>然后运行/patch TRIAGE.json --repo <repo>— 两者都会写入其启动目录,因此在该目录运行会将结论和补丁写在事件条目旁边 - 对 dnr 目标运行:
python <target>/grade.py {RUN}/INCIDENTS.json进行自评分(由用户运行) - 由人工审查并执行(或驳回)每项拟议操作;
RESPONSE.md中的内容均尚未执行
在演示基础上自定义
- 每次向其提供一条真实告警队列中的告警——负责人解析器可接收任何 JSON 或文本告警;方法不变。
- 身份验证日志、CDN/WAF 导出数据和 EDR 威胁事件可作为额外的实体活动来源加入阶段 1;保留单一的合并时间线。
- 阶段 4 的计划模板最值得按组织实际情况调整:将遏制措施映射到你们的实际控制手段(WAF 规则、IdP 会话撤销、功能标志),但仍须作为提案交由负责团队处理,绝不能由 Agent 执行。