何时使用
当你拿到一条具体的疑似安全漏洞,需要判定它是「真阳(TRUE POSITIVE)」还是「误报(FALSE POSITIVE)」时使用。典型请求:
- 「这个 bug 是真的吗 / 是不是真阳?」
- 「这是误报吗 / 帮我核验这条发现」
- 「检查这个漏洞能不能被利用」
- 任何针对单条已知漏洞的核验、验证、复核请求。
不该用的边界(命中则改用别的技能):
- 主动挖洞、做安全分析、审计整份代码(这是「找 bug」,不是「核验某个 bug」)。
- 通用代码评审:风格、性能、可维护性。
- 功能开发、重构等非安全任务。
- 用户明确只要快速扫描、不要核验。
先拒绝这些自我合理化(出现任一立即停手,回到流程):
- 「剩下的 bug 快速过一遍就行」→ 每个 bug 都要走完整核验。
- 「这模式看着危险,所以是漏洞」→ 模式识别不等于分析,必须先追完数据流。
- 「为了效率跳过完整核验」→ 不允许部分分析。
- 「这代码看着不安全,直接报」→ 上游可能已有校验,必须从 source 追到 sink。
- 「别处类似代码有洞,所以这里也有」→ 每处上下文的校验/调用方/防护都不同,独立核验。
- 「这显然是 critical」→ LLM 天然倾向于看到 bug 并高估严重性,必须做唱反调评审、用证据证明。
步骤
Step 0 — 复述主张与上下文。 分析前先用自己的话重述这个漏洞主张;说不清就用提问澄清。约一半误报在这一步就崩了——主张被精确复述后根本讲不通。记录:
- 确切漏洞主张(如「
parse_header()在content_length>4096时堆缓冲区溢出」)。 - 所称根因、所称触发方式、所称影响。
- 威胁模型:代码以什么权限运行?是否沙箱化?攻击者在触发前已能做什么?(如「未认证远程攻击者」vs「特权本地用户」;「跑在渲染器沙箱内」vs「以 root 运行无沙箱」)
- 漏洞类别:分类后按类别套用专属核验要求。
- 执行上下文、调用方约束、架构上下文、历史上下文(近期改动 / 已知问题 / 既往评审)。
选路 — 标准核验 vs 深度核验。 默认从标准开始;标准流程内置两个升级检查点,复杂度超出线性清单时自动转深度。
- 标准核验(需同时满足):主张清晰具体;单组件、无跨组件;漏洞类别成熟(溢出 / SQLi / XSS / 整数溢出等);触发不涉并发/异步;数据流从 source 到 sink 直白。
- 深度核验(满足任一):主张含糊有多种解读;跨组件路径(数据流经 3+ 模块/服务);触发涉竞态 / TOCTOU / 并发;无明确规约的逻辑漏洞;标准核验不确定或被升级;用户明确要求完整核验。深度核验为每个 bug 建任务依赖图,用
data-flow-analyzer、exploitability-verifier、poc-builder等 agent 并行跑各 Phase(Phase 3 影响、Phase 5 唱反调、Gate Review 不外包)。
标准核验六步清单:
- 数据流:从 source 追到所称 sink。标出跨越的信任边界;找出全部校验/净化;核对 API 契约(很多 API 自带边界保护);核对环境防护(编译器/运行时/OS/框架)是否彻底阻止利用。关键坑:孤立看漏洞代码——上游条件逻辑可能让它在数学上不可达。升级检查:若有 3+ 信任边界、回调/异步控制流、或校验链含糊 → 转深度。
- 可利用性:证明攻击者能触发。证明攻击者控制到达危险操作的数据(可信组件写入的内部存储不算攻击者可控);整数/边界类做显式代数证明(
IF 校验通过 THEN 边界保证成立);竞态类证明并发访问确实可能(单线程初始化、同步上下文无竞态)。 - 影响:区分真实安全影响(RCE / 提权 / 信息泄露)与运维健壮性问题(崩溃恢复、清理失败);区分主防护与纵深防御——纵深防御失效在主防护完好时不算漏洞。
- PoC 草图:写伪代码 PoC 展示攻击路径(标准核验下可执行/单测 PoC 可选)。
- 唱反调抽查:回答 7 问,任一产生无法消解的真实不确定 → 转深度。
- 闸门评审:套用六道闸门 + 13 条误报清单,得出裁决。
指令
唱反调 7 问(Step 5)——前 5 问反对漏洞、后 2 问保护防漏判(防止 false negative):
- 我是因为模式「看着危险」才认定漏洞,而非它真的危险吗?(模式匹配偏差)
- 我是否错误假设攻击者能控制可信数据?(信任边界混淆)
- 我是否严格证明了漏洞的数学条件能发生?(证明严谨性)
- 我是否把纵深防御失效当成了主防护漏洞?(纵深防御混淆)
- 我是否在幻觉这个漏洞?是真实可利用,还是在对吓人的代码做模式匹配?(LLM 自检)
- 我是否因为利用「看起来复杂/不太可能」就否掉了真实漏洞?
- 我是否凭空编造了源码里未经核实的缓解/校验逻辑?得出结论后重读代码。
六道闸门(全过才能判真阳,任一失败即误报):
| 闸门 | 判据 |
|---|---|
| 1. 流程 | 每个 Phase 都有书面证据 |
| 2. 可达性 | 攻击者可达并控制漏洞处数据,PoC 佐证 |
| 3. 真实影响 | 利用导致 RCE / 提权 / 信息泄露(非仅运维问题) |
| 4. PoC 验证 | PoC(伪代码/可执行/单测)展示了控制+触发+影响 |
| 5. 数学边界 | 代数证明漏洞条件可能成立(而非被校验数学阻止) |
| 6. 环境 | 无环境防护彻底阻止利用(ASLR/栈金丝雀只抬高门槛,不消除漏洞) |
裁决格式:
- 真阳:
BUG #N TRUE POSITIVE — <漏洞简述> - 误报:
BUG #N FALSE POSITIVE — <否决理由>
任一 Phase 核验失败:先记录失败证据,走完其余全部 Phase,再下误报裁决。
批量三连(一次核验多个 bug): ①先对所有 bug 跑 Step 0(复述主张常当场击穿明显误报);②各自独立选路(有的标准、有的深度);③先处理标准路、再处理深度路;④全部核验完后检查利用链——单独过不了闸门的发现可能组合成可行攻击。
最终汇总: ①计数(X 个真阳、Y 个误报);②真阳清单(各带漏洞简述);③误报清单(各带否决理由)。
示例
误报裁决示例(数学边界闸门拦截):
BUG #3 FALSE POSITIVE — packet_handler.c:142 整数下溢
闸门 5(数学边界)失败:第 98 行校验保证 packet_size >= 16,
故 (packet_size - header_size) >= 8,下溢在数学上不可能。
PoC 草图模板(Step 4):
数据流: [Source] → [校验?] → [变换?] → [危险操作] → [影响]
攻击者控制: [控制什么输入、如何控制]
触发: [展示利用路径的伪代码]
注意事项
- 追完整条校验链,别看孤立片段。 反向回溯危险操作前的所有校验;
buffer[length-4]看着不安全,但若代码仅在length>12时可达,则漏洞不可能。 - 辨别防御性编程与真漏洞。
ASSERT(size == expected_size)后接受控操作是防御,不是漏洞——核实检查确实阻止了所称漏洞。 - 区分数据来源信任级。 API 返回值、编译期常量、网络数据风险画像不同;可信组件在安装/初始化期写入的内部存储非攻击者可控。
- TOCTOU 需证明被检查值可在 check 与 use 之间改变;同函数内检查后立即使用、外部无法修改,就没有 TOCTOU。
- 竞态需证明并发确实可能;先确认线程模型与同步机制。
- 吃透 API 契约再断言溢出;不少 API 自带边界保护,无论入参如何都无法越界写。
- 环境缓解 ≠ 消除漏洞:区分「彻底阻止利用」(如 Rust 安全类型系统)与「只是更难」(如 ASLR、栈金丝雀)。
- 清单要系统性逐条套用到每个 bug,而非走过场——有清单不代表不会误报。
互见
code-reviewer:通用代码评审(风格/性能/可维护性),与本条的安全核验定位互补。dependency-auditor:依赖与供应链安全审计,可作为漏洞来源的上游环节。fact-checking:以证据驱动的核验纪律,与本条「拿证据说话、拒绝模式匹配」一脉相承。first-principles-thinking:从第一性原理推理、对抗 LLM 看洞偏差,支撑唱反调评审。
本条采编自 trailofbits/skills(CC-BY-SA-4.0)。