Circom 验证库漏洞CVE-2023-33252修复方案
此前,Beosin 安全研究人员在 SnarkJS 0.6.11及之前的版本 的库中发现了一个严重漏洞, 当该库在验证证明时未对参数进行完整的合法性检查,使得攻击者可以伪造出多个证明通过校验,实现双花攻击。 SnarkJS 是一款用于构建零知识证明的开源 JavaScript 库,广泛应用于 zk-SNARK 技术的实现和优化。
Beosin在提了这个漏洞以后,第一时间联系项目方并协助修复, 目前该漏洞已修复完成。 Beosin提醒所有使用了SnarkJS库的zk项目方可将SnarkJS更新到 0.7.0版本!以确保安全性。
现在,Beosin以长文的形式与大家分享漏洞原理,以及提醒项目方需要注意什么。
前言
Circom是基于Rust开发的零知识证明电路编译器,该团队同时开发了SnarkJS库用于实现证明系统,包括:可信设置、零知识证明的生成和验证等,支持Groth16、PLONK、FFLONK算法。
2. 漏洞原理
Beosin安全实验室漏洞研究人员在SnarkJS小于等于0.6.11版本中发现,当该库在验证证明时未对参数进行完整的合法性检查,使得攻击者可以伪造出多个证明通过校验,实现双花攻击。数学依据: 首先如果要在以太坊中生成和验证zk-SNARK证明,需要使用 F_p-arithmetic 有限域椭圆曲线电路,其中曲线的一般方程如下:
可以发现曲线上的点都会进行一个模p运算,所以电路生成的证明参数s值取值范围为[0,1,…,p-1],那么当SnarkJS的变量范围大于电路取值范围时,存在下列多个具有相同输出的证明参数值:
综上,只要知道了其中一个合法的证明参数s,参数范围内的s+np( n = 1,2,…,n)都可以满足验证计算,于是攻击者在获取到任意验证通过的s,即可构造多个s可以通过校验,具体的攻击流程如下:
上文可知,参数的取值范围由p决定,而不同类型的F_p对应不同的p,需要根据具体使用的零知识算法确定。
3. 漏洞实现
使用snarkjs库进行链下验证时,在groth16Verify函数中并未校验publicSignals参数的取值范围合法性,导致可以伪造证明通过校验:
4. PoC
初始的originalHash验证通过,接着使用刚伪造的attackHash同样验证通过!即同一份proof,可以被多次验证通过,即可造成双花攻击。
此外,由于本文使用ALT_BN128 曲线进行复现,因此共计可以生成6个不同参数通过验证:
4. 修复方案
Circom 项目已经针对该通用漏洞进行了修复,涉及到其实现的共计3个算法:
1)groth16_verify.js
2)flonk_verify.js
3)plonk_verify.js
针对此漏洞, Beosin安全团队提醒zk项目方,在进行proof验证时,应充分考虑算法设计在实际实现时,由于代码语言属性导致的安全风险。同时,强烈建议项目方在项目上线之前,寻求专业的安全审计公司进行充分的安全审计,确保项目安全。
5. 漏洞后续
目前该漏洞已经被收录到github advisory database中,且为评分7.5的高危漏洞:
同时该高危漏洞也被更新到npm库中,安装旧版本snarkjs库时会有如下预警信息:
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
Justin Sun suspected to have purchased $160m in Ethereum
Justin Sun suspected to have purchased $160m in Ethereum