CVE-2024-48930 — secp256k1 (npm) ECDH Private Key Extraction
Discusses the vulnerability mechanism, impact scope and upgrade guidance for private-key extraction in the secp256k1 package under ECDH scenarios.
这就是那个 2024 年 的 CVE:npm 包
secp256k1(cryptocoinjs/secp256k1-node的elliptic.js纯 JS 版本)因为压缩公钥加载时缺少曲线校验,攻击者可用中国余数定理从至多 11 次 ECDH 会话中还原完整私钥。
1. 基本信息
| 项 | 值 |
|---|---|
| CVE | CVE-2024-48930 |
| GitHub Advisory | GHSA-584q-6j8j-r5pm |
| 影响包 | secp256k1(npm) |
| 影响路径 | secp256k1/elliptic.js(纯 JS 实现,非 native gyp 版本) |
| 漏洞类型 | CWE-200(信息泄露)/ CWE-354(完整性校验缺失) |
| 严重度 | CVSS 4.0:AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N(High) |
| 发布时间 | 2024-10-21 |
受影响版本 & 修复
| 版本区间 | 修复版本 |
|---|---|
0 ~ 3.8.0 | 3.8.1 |
4.0.0 ~ 4.0.3 | 4.0.4 |
5.0.0 | 5.0.1 |
2. 漏洞成因(代码层面)
库在加载公钥时,对「非压缩公钥」做了曲线校验,但对「压缩公钥」漏掉了:
// loadUncompressedPublicKey —— 有校验
if (!this.curve.validate(point)) { ... } // ✅ 会检查点是否在曲线上
// loadCompressedPublicKey —— 缺失校验
// 直接根据 X 恢复 Y,没有校验 (X, Y) 是否真的满足 y² = x³ + 7
恢复 的过程本质是:
当给定的 使得 不是模 的二次剩余(即正确曲线上无解)时,这段代码会落到另一条曲线:
得到一个位于「另一条曲线」上的点,而那条曲线的群阶往往可分解,含低阶子群。于是攻击者可以构造低阶点 ,让受害者用它计算 ECDH。
3. 利用原理
设受害者私钥为 ,攻击者发来的恶意点 阶为 :
ECDH 输出 只泄漏余数 。攻击者对每条含低阶子群的曲线重复,得到:
再用中国余数定理合并(原理详见无效曲线攻击与CRT私钥恢复.md):
官方 Advisory 原话(关于 CRT)
Those output values correspond to remainders which can then be combined with Chinese remainder theorem to restore the original value.
规模数据
- 10 个精心构造的恶意 值即可泄漏约 238.4 bit(256 bit 私钥);
- 再用第 11 个(任意)公钥补齐剩余位,即可完整还原;
- 攻击者无需拿到 ECDH 明文输出,只要能「确认某个候选值」即可(例如用它解出的密文是否正确),因此甚至可以在本地离线完成;
- 预计算在单台 MacBook Air 上数天,实际提取约 10 分钟。
4. 攻击流程
flowchart TD
A["构造压缩恶意点 P<br/>其 X 使 X³+7 非二次剩余"] --> B["loadCompressedPublicKey<br/>落到另一条曲线 Y²=X³+D"]
B --> C["得到低阶点 P(阶 l)"]
C --> D["受害者 ecdh(P, d) → S = [d]P"]
D --> E["暴力枚举恢复 r = d mod l"]
E --> F{"凑够 10~11 个?"}
F -->|否| A
F -->|是| G["CRT 合并 → 完整私钥 d"]
4.1 迷你椭圆曲线 PoC(可运行 + 动画)
这个 CVE 的数学本质可以用一段纯 JS 的迷你椭圆曲线代码完整复现:
- 可运行 PoC:
assets/invalid_curve_attack.js(node invalid_curve_attack.js) - 动画演示(SVG,需
<iframe>嵌入或直接打开):
它在模 97 的曲线 上,从扭曲曲线 ()构造阶为小素数(2/3/7/13/31)的点,做 ECDH 恢复 ,再用 CRT 还原私钥 。
5. 影响
- 远程、无需任何权限即可完整提取私钥;
publicKeyVerify()会对恶意公钥错误返回true;publicKeyTweakMul()等其它公钥运算同样可被用来恢复 tweak。
6. 修复
给 loadCompressedPublicKey 补上与 loadUncompressedPublicKey 一致的曲线点校验(curve.validate),确保解出的 真的满足 。
相关提交:
8bd6446e000fa59df3cda0ae3e424300747ea5ed9a15fff274f83a6ec7f675f1121babcc0c42292fe256905ee649a7caacc251f7c964667195a52221