一个动手实践的演示,展示如何用 ReGrade 进行零日漏洞发现。 你将把一套普通测试套件指向 ReGrade,让它针对一个小型服务录制流量,再对同一服务的第二个副本 重放,然后用 Claude Code + ReGrade MCP 工具 暴露一个密码哈希泄露——一个没有任何测试是为发现它而编写的漏洞。
它模拟了一个真实 bug:CVE-2023-5968,一个协作平台的用户名更新端点返回了完整用户对象,包括 bcrypt 密码哈希。该漏洞于 2017 年上线,存活了 7 年,躲过了测试、审查和审计。(Curtail 的博客文章。)
关键点: 这里没有 v2。你让应用与它自己对比。新实例会用不同的 bcrypt salt 对密码做哈希,因此泄露的哈希值在两个副本之间是不同的——而正是这种熵被 ReGrade 标记出来。该漏洞潜伏在你已经发布的代码中;发现它不需要任何版本变更。
regrade 传感器,并设置 REGRADE_API_KEY(或 ~/.regrade/key)。claude plugin marketplace add https://app.regrade.curtail.com/downloads/latest/marketplace.json
然后执行 claude plugin install regrade@regrade --scope user,并连接一次(/mcp,
用与你的 key 相同的账号登录)。一个微型“团队聊天” API(app/store.py),包含用户和频道。Docker Compose 运行两个完全相同的副本——同一镜像、同一代码、没有版本标志:
http://localhost:8001 — 对它进行录制。http://localhost:8002 — 对它进行重放。其中一个端点埋了一个缺陷:
| 端点 | 行为 |
|---|---|
GET /users/<id> | 已消毒 — 从不返回密码。干净的基线。 |
PATCH /users/<id> (rename) |
密码在启动时进行 bcrypt 哈希,因此 instance-a 和 instance-b 对同一用户持有不同的哈希。
git clone https://github.com/Curtail-Inc/hello-ReGrade-security
cd hello-ReGrade-security
docker compose up -d --build
traffic/test_api.py 是一套普通的功能测试:登录、读取用户、重命名用户、列出频道。它断言 CRUD 行为,不做任何安全断言——从不检查 password 是否泄露。(为什么要检查呢?没人知道这个 bug 存在。)
在 instance-a 前面启动传感器代理:
regrade proxy --target http://localhost:8001 --port 19870
在另一个终端里,运行同一套测试套件——只需把 BASE_URL 指向代理。这是唯一的改动:
BASE_URL=http://localhost:19870 python -m pytest traffic/test_api.py
所有测试照常通过,无需修改。停止代理(Ctrl-C);录制会上传并打印一个 Recording ID: <uuid> — 记下它。
regrade replay --rec-id <RECORDING_ID> --target http://localhost:8002
两边的代码相同——唯一的差异是新实例生成的各类值。
在本仓库中打开 Claude Code,让它带你走一遍重放流程。在本仓库的 CLAUDE.md 引导下,它会:
summarize_deltas → 得到若干 delta:登录 token、频道 created_at 时间戳,
以及——悄然混在其中的——$.password。$.token 创建 create_id_mapping(动态 ID,不是该丢弃的噪声),$.channels[*].created_at 创建 create_filter_rule DROP(每次启动都会变化的时间戳),apply_profile_to_replay,然后 query_deltas(unlabeled_only=true) —— 重复直到只剩一个
delta。$.password — 响应体中的一个 bcrypt 哈希。
一个 CVE 级别的泄露,在零先验知识、零安全断言的情况下被发现。会话 token 和密码哈希在两次运行之间都会不同——两者都是每次都会变化的高熵字符串。一个是合法的噪声,你可以映射;另一个是泄密。你无法用“它变了”来区分它们——你必须看变了的是什么。如果把每个高熵字段都当作噪声过滤掉,你就会把这个漏洞藏起来。
这就是教训:ReGrade 不校验预期,它对比行为——因此它能浮现出没人想到要为它写测试的那些 bug。
app/store.py 只有一个文件。GET 路径会调用 sanitize();PATCH 路径忘了调用。等你用 ReGrade 找到它之后再去看代码——关键在于,ReGrade 仅凭流量、通过应用与自身的对比就抓到了它。
Apache-2.0.
那个 bug — 返回完整的用户对象,包括 bcrypt password 哈希。缺少一次 sanitize() 调用,与 CVE-2023-5968 如出一辙。 |