只因缺少这“3 行代码”,黑客凭空获取 200 万个 BNB!
2022-10-09 11:00
欧科云链
2022-10-09 11:00
订阅此专栏
收藏此文章

北京时间 2022 年 10 月 7 日,据欧科云链链上卫士安全团队监测,BNB Chain 遭遇有史以来金额最大的黑客攻击。据链上数据显示,10 月 7 日黑客利用跨链桥漏洞分别于 2 点 26 分、4 点 43 分共获取 200 万个 BNB,价值约 5.66 亿美元(按发生时价格计算)

与以往跨链桥攻击不同的是,此次黑客攻击获取的 200 万个 BNB 并非从链上用户的账户中偷盗而来,而是通过 BNB Chain 跨链桥的安全漏洞,凭空增发出来的

这里需要强调的是,虽然攻击手法不同,但凭空生成的大量资产流入市场与资产被盗带来的影响一样,均会对当前市场带来严重的负面影响,甚至需要广大用户为项目方的安全事故买单。

关于此次事件的经过,欧科云链链上卫士团队已第一时间进行了时间线梳理(以下均为北京时间)

1

10 月 6 日 7 点 27 分

黑客使用 ChangeNOW 服务转入了 100 多个 BNB 到BNB Chain上,作为起始攻击资金。

2

10 月 7 日 0 点 55 分

黑客调用系统 RelayerHub 合约 0x1006 进行注册,成为 relayer。

3

10 月 7 日 2 点 26 分、4 点 43 分

黑客使用BNB Chain跨链桥的漏洞盗取 200 万个 BNB

4

10 月 7 日 2 点 31 分、2 点 37 分

黑客使用 Venus 的借贷服务,抵押了 90 万个 BNB,从里面借走了 5000 万 USDT、6250 万 BUSD 和 3500 万 USDC。然后通过 Stargate 跨链桥,将资产转移到 ETH、AVAX、FTM 等网络上,总计转出资产约为 9000 万美金。

5

10 月 7 日 6 点 19 分

币安暂停 BNBChain 链

6

10 月 7 日 15 点左右

币安宣布重新开放BNBChain的同时,BSC 节点程序通过黑名单与暂停 iavlMerkleProofValidate 功能2 种方式,阻止被盗资金流动与潜在的攻击。

缺少“3 行代码”

BNB Chain增发 200 万个 BNB

BNB 信标链(BEP2)是币安基于 Cosmos 开发的一条应用链,BNB Chain链(即 BSC 链,支持 BEP20 资产)是兼容 EVM 的一条链,BSCTokenHub 是 BNB 信标链和 BNB 链之间的跨链桥。

正常状态下,BNB Chain链使用预编译合约 0x65 验证 BNB 信标链提交的 IAVL 的 Proof,对提交的 Proof 进行校验,校验成功后在BNB Chain链上 Mint 对应的 BNB。

而此次黑客事件发生,主因是BNB Chain链对提交的 Proof 边界情况处理不足,它仅考虑了 Proof 只有一个 Leaf 的场景,对多个 Leaves 的处理逻辑不够严谨。黑客通过构造了一个包含多 Leaves 的 Proof 数据,绕过 BNB Chain 上的校验,从而在BNB Chain链增发了 200 万个 BNB。

通过对漏洞的解析及BNB Chain链最新代码,链上卫士团队发现在同样的位置,事故发生前并没有这“3 行代码”

此段代码,是指 IVAL 库在计算 Hash 过程需要考虑 pin.Left 和 pin.Right 均大于 0 的情况,事故发生后官方增加此段代码,是为了可以避免发生同类情况。

这里以其中一次攻击交易(增发 100 万个 BNB)为例:

0xebf83628ba893d35b496121fb8201666b8e09f3cbadf0e269162baa72efe3b8b

黑客构造输入数据 payload 和 proof,输入参数通过 validateMerkleProof 校验,返回值为 true。

在后续 IApplication(handlerContract).handleSynPackage 处理中,合约给黑客增发 100 万个 BNB。

解析黑客手法:函数调用过程

链上卫士团队第一时间解析了此次黑客攻击手法,交易首先调用 CrossChain 合约 0x2000 的 handlePackage 函数:

handlePackage 会进一步调用 MerkleProof.validateMerkleProof 对输入的 proof 进行校验:

MerkleProof 相关代码可以看到,实际的验证逻辑是使用预编译合约 0x65 完成:

https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/MerkleProof.sol#L66

系统预编译合约 0x65 对应 iavlMerkleProofValidate 功能:

https://github.com/bnb-chain/bsc/blob/f3fd0f8bffb3b57a5a5d3f3699617e6afb757b33/core/vm/contracts.go#L81

系统合约 0x65 实现代码如下,主要逻辑为使用 DecodeKeyValueMerkleProof 解码输入参数,并调用 Validate 进行校验:

https://github.com/bnb-chain/bsc/blob/master/core/vm/contracts_lightclient.go#L106

其中 kvmp.Validate() 实现代码如下:

https://github.com/bnb-chain/bsc/blob/master/core/vm/lightclient/types.go#L220-L234

DefaultProofRuntime 构造函数使用 IAVL 库进行 Proof 的验证:

罪魁祸首:IAVL 代码问题

IAVL 的 Proof 校验过程中,Hash 计算存在漏洞,导致黑客可以在 Proof 添加数据,但计算 Hash 时并没有用到添加的数据。详细分析如下:

在 len(pin.Left) 不为 0 的分支中,计算 Hash 并没有使用 pin.Right 数据。黑客利用该处漏洞构造数据,添加 proof.LeftPath[1].Right 数据,但是该数据并不参与 Hash 计算。

https://github.com/cosmos/iavl/blob/master/proof.go#L79-L93

根据上述分析,正常数据组织结构如下,proof.LeftPath[1].Right 为空值,计算得到正确的 Hash。

proof.LeftPath = len(2)

proof.LeftPath[0]是一个正常数据,proof.LeftPath[1].Left 是一个正常数据,proof.LeftPath[1].Right 空值

proof.InnerNodes = len(0)

proof.Leaves = len(1),proof.Leaves[0]是一个正常数据

黑客构造攻击数据结构如下,添加 proof.LeftPath[1].Right 数据,且该数据不参与 Hash 计算。

proof.LeftPath = len(2)

proof.LeftPath[0]是一个正常数据,proof.LeftPath[1].Left 是一个正常数据,proof.LeftPath[1].Right 是一个伪造数据

proof.InnerNodes = len(1), InnerNodes[0]=nil

proof.Leaves = len(2),proof.Leaves[0]是一个正常数据,proof.Leaves[1]是一个伪造数据

且 proof.LeftPath[1].Right = COMPUTEHASH(proof.Leaves[1])

IAVL 的 Proof 校验代码如下,主体逻辑为 COMPUTEHASH 递归调用。

由于 lpath.Right 也为黑客输入数据,使得黑客构造的数据能够通过 bytes.Equal(derivedRoot, lpath.Right) 的校验,并返回上一轮 COMPUTEHASH 通过 proof.Leaves[0]计算的结果,该结果为正常数值,从而绕过了 IAVL 的 Proof 校验。

黑客攻击构造的数据中,包括了 IAVL:V 和 multistore 相关数据,multistore 数据也是基于 IAVL 进行操作,原理是一样的,不再进行详细分析。

这次 IAVL Proof 暴露的问题在于,数据局部的变化无法反应到整体,使得校验发生错误。在 Cosmos 生态中,IBC 使用 ICS23 来做数据的校验处理,ICS23 与 IAVL Proof 校验不同点在于,ICS23 会对所有的“叶子节点”的值进行数据校验,最后计算得出的根 Hash 再与链上数据进行校验,OKC 采用的是 ICS23 的 Prove,因此不存在 BNBChain 这次遇到的安全漏洞。

链上卫士复现漏洞真实存在

链上卫士团队利用黑客攻击交易数据,基于 BNBChain 单元测试代码,增加了基于黑客攻击交易的测试用例,可以完整复现黑客的攻击交易。

单元测试代码利用 iavlMerkleProofValidate.Run 接口验证输入数据,即相当于调用预编译合约。

https://github.com/BananaLF/bsc/blob/bsc-hack/core/vm/contracts_lightclient_test.go#L99-L100

利用黑客攻击交易数据,构造新的 payload 数据为 value := []byte(“okc test hack”),并对 proof 相应数据进行了修改,即修改 proof.LeftPath[1].Right 和 proof.Leaves[1]对应的数据,新构造的数据可以通过 okcIavlMerkleProofValidate 校验,即修改了黑客数据也能通过校验。

另外,如下单元测试代码对原始黑客数据和修改后的数据两种 case 都进行了校验,且校验都能成功,从而说明如下测试代码利用本文所述漏洞成功进行了复现。

https://github.com/BananaLF/bsc/commit/697c5cd73a755a7c93c0ed6c57d069e17f807958

跨链桥再次敲响安全警钟

跨链桥,作为区块链的基础设施之一。其自身的中心化特性,为去中心化的 Web3 世界引入了中心化风险,其安全性很大程度上取决于跨链桥项目方自身。

本次黑客攻击通过构造了一个包含多 Leaves 的 Proof 数据,绕过 BNBChain 上的校验,从而在 BNB 链造成了 BNB 增发。相较以往线下漏洞、私钥泄露等攻击方式,这次攻击难度更高,且涉及金额更大,据统计涉及金额在 8.5 亿左右,创下历史新高。

目前 OKLink 多链浏览器已对 BNB Chain 黑客地址进行风险标签标记(标记为“Hack”),关于此次被盗后续,链上卫士团队还将进一步追踪案件细节并及时同步。

相关Wiki

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

在 App 打开
hyperliquid
wal
jellyjelly
particle
空投
香港
以太坊
rwa
movement
bera
monad
sui