← Blog

一个普通人模仿顶级黑客获得 CVE 的经历 (副标题:你也得做到)

前言

我是一个极其普通的人。

虽然我是计算机科学专业,但毕业前的安全经验为零。去年这个时候(2025年4月),我的全部成果不过是侥幸向 KISA 提交了一个 Stored XSS。

然而,我利用 AI 在周下载量 5000 万次的 npm 包(TanStack Query)和 Apache Airflow 等大型开源项目中发现了漏洞,并成功获得了 CVE。

CVE ID 目标 漏洞类型 严重程度
CVE-2026-26903 TanStack Query 无限递归导致的 DoS Medium
CVE-2026-25604 Apache Airflow AWS Auth Manager Host Header 注入 Medium

这篇文章是写给那些在想我也能做到吗? 的朋友们——因为答案是是的,你也可以


开始:在互联网上发现绿洲

始于Seokchan Yoon的一篇博客文章。

用 $5 的提示词找到价值 $2,418 的漏洞

这篇文章我反复精读了无数遍。遇到不理解的地方就喂给 Claude 让它解释,如此反复。

借此机会,向Seokchan Yoon先生表达诚挚的感谢。


我做了什么,怎么做的?

工具:Claude Pro + Claude API

没有什么花哨的东西。一个 Claude Pro 订阅和 Claude API——仅此而已。

Step 1:构建扫描器

基于尹锡灿的文章,我指示 Claude 构建一个漏洞扫描器。从简单的结构(v1)开始,通过不断减少误报(False Positive),一路迭代到 v3

让我惊讶的是,Claude 会自己升级自己。当我持续把 v1 的结果反馈给 LLM 时,它会说:”如果把检测逻辑改成这样,可以同时优化成本和误报率”——v2 和 v3 就是这么诞生的。

以下是 Claude 自行构建的 v1 到 v3 的内容。

v1:”找 bug 就行” —— 天真的第一版

“你是一名安全研究员。找出代码中的安全漏洞。”

这几乎就是整个系统提示词。架构也很简单:

  1. git clone 一个仓库
  2. 将源代码文件切成 ~25K token 的块
  3. 每个块加上一个提示词发送给 Claude
  4. 解析 XML 结果

技术上来说,它能工作。问题是?它什么都报。一个接受 command 参数的库函数?”命令注入!”一个接受文件路径的开发者 API?”路径遍历!”一个设置数据库 URL 的配置选项?”SSRF!”

我拿几个仓库试了试,结果涌出了几百个发现。几乎全是垃圾。误报率大概超过了 95%。

这时Claude意识到:扫描器根本没有谁在调用这个函数?这个概念。它把每个参数都当成攻击者直接输入的。


v2:多阶段流水线 —— 加入一个怀疑论者

v2 的核心洞察是:不要只找 bug,还要尝试反驳它。

我把扫描器重构为多阶段流水线:

  • Phase 1 — 侦察(Reconnaissance):不直接跳入漏洞分析,而是先绘制攻击面。HTTP 处理程序在哪里?eval()exec() 等危险 sink 在哪里?哪些文件值得深入分析?
  • Phase 2 — 深度分析(Deep Analysis):只分析侦察阶段标记的文件。提示词要求具体的攻击向量——如果你不能一步步说明如何利用它,就不要报告。
  • Phase 3 — 对抗性验证(Adversarial Validation):这才是真正的 game changer。我用不同的人设把每个发现再次发给 Claude:“你是一个持怀疑态度的安全审查员。你的任务是反驳这个发现。”它会检查:输入真的是用户可控的吗?有没有做过滤?这条代码路径在生产环境中真的可达吗?

我还加入了文件优先级评分系统。包含 HTTP 路由处理程序(app.get()@PostMapping)和用户输入模式(req.bodyrequest.form)的文件优先级提升,测试文件、配置文件和仅开发环境的代码则被自动过滤。

误报率显著下降了。但 v2 有一个无法解决的根本问题。


v3:信任边界分析(Trust Boundary Analysis)—— 突破口

在运行 v2 的过程中,我不断看到同样模式的误报:

“这个库有一个 execute(query) 函数,不做参数化就执行 SQL——SQL 注入!”

但这个函数是一个库的 API。导入这个库的开发者自己选择传入什么。开发者是可信的主体。这不是漏洞,这是功能。

在扫描 npm 包和 Java 库时,这是最大的误报来源。于是我构建了 Phase 0:目标分类(Target Classification)

在开始扫描之前,v3 首先回答这个问题:“这个代码库是什么?”

它将目标分为四种信任模型:

类型 谁是可信的? 什么才算真正的漏洞?
APPLICATION 用户不可信 HTTP 输入 → 危险 sink
LIBRARY 开发者可信 仅当外部数据在没有开发者介入的情况下到达 sink
FRAMEWORK 插件开发者可信 仅当框架核心错误处理用户输入
CLI_TOOL 混合 处理的文件、网络响应

扫描器通过分析 package.json 字段(mainmoduleexports → 库)、代码模式(app.get()req.body → 应用程序)和结构性指标来自动检测类型。

之后,所有后续阶段都使用这个信任上下文。侦察提示词对库和应用程序提出不同的问题。深度分析提示词包含针对每种信任模型的专用规则。关键的是——在库目标中,被标记为 requires_malicious_developer: true 的发现会被自动过滤。

找到两个 CVE 的正是这个版本。信任边界过滤器消除了噪音,不可信的终端用户输入真正到达危险 sink 的真实漏洞清晰地浮现出来。


实际上是怎么做的

大部分代码不是我自己写的。

我的工作流程是这样的:

  1. 反复阅读并理解尹锡灿的原始方法
  2. 向 Claude 详细描述我想要的东西——架构、阶段、提示词
  3. 审查输出——这是我的安全知识发挥作用的地方
  4. 在真实仓库上测试并分析失败原因
  5. 把失败案例反馈给 Claude:”这是误报。为什么会这样?怎么防止?”
  6. 迭代——v1 → v2 → v3 每一版都源于理解上一版为什么失败

我认为这里的关键在于:当 Claude 提出版本升级方案时,你要能判断它是否合理。如果我只是因为 Claude 说了就无脑照做,扫描器的性能反而可能会变差。

Step 2:扫描-> 审查-> 提交

在将扫描器迭代到 v3 之后,我根据扫描结果撰写了报告并提交。

我把热门开源项目——Spring、npm 包等——按下载量排序,然后逐个进行:git clone → 扫描 → 重复。总共扫描了 100 多个仓库,整个 2026 年 1 月都投入在这上面。

扫描器的原始输出(XML)不能直接当报告用。我把每个结果连同实际源代码一起发给 Claude 做最终审查——这是误报还是有效漏洞?我没有盲目信任自动化结果,而是把 LLM 当作二次验证员来使用。

对于通过最终审查的发现,我撰写报告并提交。报告撰写同样借助了 AI——我让 Claude 学习其他人的 CVE 报告并生成草稿。除了证据(PoC 截图、代码)之外的部分几乎都是 Claude 写的,我只负责审查。

结果

  • 扫描的仓库:100+
  • 提交的报告:4 份
  • 获得的 CVE:2 个
  • 耗时:约 1 个月(2026 年 1 月)
  • API 费用:约 ₩70,000(约 ¥350),Claude Pro 订阅费另计

100 多个仓库扫描下来,提交了 4 份报告,2 份被认定为 CVE。命中率确实很低。


感悟:成为善用 AI 的人

我是一个在 AI 出现之前从未尝试过寻找 CVE 的人。那些前辈们到底用什么样的思维过程来发现漏洞,我完全摸不着头脑。

但在 AI 时代,我亲自证明了即使是像我这样的普通人也能获得 CVE。

说实话,既高兴又害怕——作为一个刚入行的新人,担心会被 AI 取代。

但经过一个月的实践,有一点我非常确定:

AI 并非万能。它只能发挥使用者本身能力的水平。

问题问得蠢,答案就蠢;问题问得聪明,答案就聪明。用过 AI 的人应该都能感同身受。

归根结底,AI 是工具,重要的是成为善于使用这个工具的人


结语

我是一个阴差阳错比别人晚起步进入黑客/安全领域的人。毕业后才真正开始。

去年这个时候(2025年4月),除了凭运气向 KISA 提交了一个 Stored XSS 之外,几乎没有什么成果。此后,我主动拜访了各路高手,一起学习研究,在漏洞赏金方面也逐渐取得了一些成果。

今年年初(2026年1月)的目标是“无论如何一定要拿到 CVE!”——跌跌撞撞之中,竟然真的实现了。

希望这篇文章能对像我一样的普通人有哪怕一点帮助。

感谢您阅读到这里。


相关链接