近4000 BTC损失:Liquid Network安全事件漏洞分析

作者:Beosin 发布:2026-09-17 23:55 收录:2026-09-18 15:10 1 次阅读 约 1654 字
摘要:对于密码学证明,验证结果往往依赖资产类型、金额承诺、脚本、交易上下文、协议版本等多个因素。遗漏任意关键字段,都可能导致验证结果被跨上下文复用
推荐理由:本文围绕「安全事件」、「漏洞」、「Beosin」等主题展开。

9月7日,Bitcoin 侧链 Liquid Network 发生了一起重大安全事件,约 4000 枚BTC 从 Liquid Federation 的 BTC 储备中被提走。攻击者利用 Liquid 底层软件 Elements 中的验证缓存漏洞,额外铸造了约 4000 枚 L-BTC;随后再通过合法的 peg-out 流程,把这些伪造出来的 L-BTC 兑换成了主网上的真实 BTC。


目前,攻击者已返还 3400 枚BTC,剩余的 598.5 枚BTC仍处于是否为“漏洞赏金”的争议中。Beosin对本次漏洞的分析如下:

 

一、漏洞分析


Liquid Network 是 Blockstream 参与开发的 Bitcoin 侧链。用户将 BTC 锁定在主网 Federation 多签地址后,可以在 Liquid 上获得等量的 L-BTC。理论上,每一枚 L-BTC 都应有一枚 BTC 作为储备支撑。


本次事件中,攻击者通过 Elements 的验证漏洞,在 Liquid 链上制造了约 4000 枚未被 BTC 支撑的 L-BTC。随后,攻击者将这些 L-BTC 发送至 SideSwap 的 peg-out 服务。SideSwap 按正常业务逻辑销毁 L-BTC,并通过有效的 Peg-out Authorization Key(PAK),向 Liquid Federation 发起提款请求。Federation 节点看到的是一笔形式上有效的 peg-out,于是释放了真实 BTC。


Liquid 使用 Confidential Transactions 和 Confidential Assets。金额和资产类型并不是完全明文暴露的,因此系统必须通过密码学证明来保证:

- 输出金额处于合法范围
- 输入输出不会凭空增发
- 资产类型和金额承诺在数学上自洽

其中 range proof 用来证明隐藏金额在合法范围内。如果没有 range proof,攻击者可能构造负数输出与更大正数输出,凭空创造资产。但 range proof 验证成本较高,所以 Elements 实现了验证缓存。这一设计本身没有问题,问题在于缓存 key 未能完整绑定所有会影响验证语义的上下文

旧版代码缓存 key 计算逻辑大致如下,只将proof和commitment两个字段存入缓存 key:

void SignatureCache::ComputeEntryRangeProof(    uint256& entry,    const std::vector<unsigned char>& proof,    const std::vector<unsigned char>& commitmentconst {    CSHA256 hasher = m_salted_hasher_range_proof;    hasher.Write(proof.data(), proof.size())          .Write(commitment.data(), commitment.size())          .Finalize(entry.begin());}
然后在 CachingRangeProofChecker::VerifyRangeProof 中,代码会先计算缓存key:

rangeProofCache.ComputeEntryRangeProof(    entry,    vchRangeProof,    vchValueCommitment);
如果缓存命中,就直接返回验证成功:

if (rangeProofCache.Get(entry, !store)) {    return true;}
但 range proof 的有效性并不能只依赖 proof 和 value commitment,攻击者只需要确保在目标节点还有缓存 Key ,把携带碰撞载荷的交易提交过去就能通过验证。其攻击流程可总结成以下5个阶段:

(1) 攻击者获得少量合法 L-BTC

攻击者最初并不需要大量资金,只需要足够的合法输入来构造后续交易、验证缓存,并让节点接受某些 proof 的验证结果。

(2) 构造可复用的 range proof 缓存项

攻击者提交一笔在特定上下文下合法的交易,使 Elements 节点把某个 range proof 的验证成功结果写入缓存。

(3) 构造语义不同但缓存Key命中的交易

由于旧版 Elements 的 range proof 缓存 key 没有完整绑定资产和脚本上下文,攻击者可以让另一笔本应重新验证、且在新上下文下无效的交易命中已有缓存。节点因此直接返回验证成功。

(4) Liquid 接受未有实际资产支撑的 L-BTC

错误验证结果使链上出现了并无真实 BTC 储备支撑的 L-BTC。从 Liquid 节点视角看,这些资产已经存在并且可以被正常花费。

(5) 通过 peg-out 兑换成真实 BTC

攻击者把伪造 L-BTC 发送给 SideSwap peg-out 服务。SideSwap 销毁 L-BTC,并向 Liquid Federation 发起合法授权提款。Federation 的 functionaries 看到销毁和授权都有效,于是释放真实 BTC。

除了底层软件 Elements 存在漏洞,SideSwap 的 peg-out 服务也存在明显的安全不足,导致大额被盗资金非常顺利地完成了跨链出金:

- 大额 peg-out 缺少人工复核
- 缺少相对于总供应量和储备规模的限额检查
- 缺少针对新钱包、新资金来源和异常交易形态的风

二、漏洞修复

Elements对该漏洞的第一次修复思路是 ComputeEntryRangeProof 不再只接收 proof 和 value commitment,而是额外加入asset commitment 和 scriptPubKey:

Hash(proof || value_commitment || asset_commitment || scriptPubKey)
但多个字段直接拼接后再哈希,如果没有长度前缀,理论上可能出现字段边界歧义,例如 A || BC 与 AB || C,这是必须要考虑的安全边界问题。

于是在第二次修复中,将先前的 CSHA256.Write() 拼接改为带序列化语义的 CHashWriter(SER_GETHASH),避免字段边界碰撞:

链接: https://github.com/ElementsProject/elements/commit/9400096

三、安全建议


Liquid Network 此次安全事件是一场由底层验证缓存缺陷引发的系统性事故,旧代码把 range proof 的验证成功结果缓存到一个上下文绑定不完整的 key 下,导致本应重新验证的无效 proof 可以通过缓存命中绕过验证。攻击者利用这一点制造未被 BTC 储备支撑的 L-BTC,再通过 SideSwap 的正常 peg-out 流程换出真实 BTC。


对于密码学证明,验证结果往往依赖资产类型、金额承诺、脚本、交易上下文、协议版本等多个因素。遗漏任意关键字段,都可能导致验证结果被跨上下文复用。此外,在业务安全方面,任何桥、侧链、L2 或托管兑换服务,都应该考虑经济安全性,判断交易行为的合理性,对于巨额交易,应考虑设置单笔限额、日限额、储备比例限制、新地址冷却期、人工审批和异常流速报警等机制。


Beosin是一家领先的区块链安全与监管合规科技公司,专注于项目上线前的智能合约安全审计、项目运行时的安全风险监控与阻断、被盗追回、虚拟资产反洗钱(AML)以及调查追踪。Beosin已为全球20多个国家和地区的监管与执法机构、200多家虚拟资产服务商以及4500多家Web3项目提供“一站式”区块链合规产品+安全服务。欢迎点击公众号留言框,与我们联系。
































转载声明:本文转载自原发布平台 (作者:Beosin), 原文标题《近4000 BTC损失:Liquid Network安全事件漏洞分析》, 查看原文。 版权归原作者及原发布平台所有,本站仅作收录与展示,未对正文内容作实质性修改; 若涉及侵权请联系本站处理。