Background of the incident In the early morning of October 7, 2022, Beijing time, BNB Chian cross-chain bridge BSC Token Hub was attacked. Hackers used cross-chain bridge vulnerabilities to acquire 2 million BNBs in two sessions, worth about US$566 million. Vulnerability Analysis

Event Background

Beijing time in the early morning of October 7, 2022, BNB Chian cross-chain bridge BSC Token Hub was attacked. Hackers used cross-chain bridge vulnerabilities to acquire 2 million BNBs in two sessions, worth about US$566 million.

Vulnerability Analysis

BSCTokenHub is a cross-chain bridge between the BNB beacon chain (BEP2) and the BNB chain (BEP20 or BSC). The BNB chain uses precompiled contract 0x65 to verify the IAVL's Proof submitted by the BNB beacon chain, but the BNB chain does not handle the submitted Proof boundary situation. It only considers the scenario where Proof has only one Leaf, and the processing logic of multiple Leaves is not rigorous enough. The hacker constructed a Proof data containing multiple Leaves, bypassing the verification on BNBChain, thus causing BNB additional issuance on the BNB chain.

Take one of the attack transactions as an example: xebf83628ba893d35b496121fb8201666b8e09f3cbadf0e269162baa72efe3b8b

Hacker constructs the input data payload and proof, and the input parameters pass the validateMerkleProof verification, and the return value is true.

In the subsequent IApplication (handlerContract).handleSynPackage processing, the contract issues 1 million BNBs to the hacker.

function call procedure

transaction first calls the handlePackage function of CrossChain contract 0x2000:

handlePackage will further call MerkleProof.ValidateMerkleProof to verify the input proof:

MerkleProof related codes can see that the actual verification logic is to use precompiled contract 0x65: https:// github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/MerkleProof.sol#L66

System precompiled contract 0x65 corresponds to iavlMerkleProofValidate function: https://github.com/bnb-chain/bsc/blob/f3fd0f8bffb3b57a5a5d3f3699617e6afb757b33/core/vm/contracts.go#L81

system contract 0x65 implementation code is as follows. The main logic is to use DecodeKeyValueMerkleProof to decode the input parameters and call Validate for verification:

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

Where kvmp.Validate() implementation code is as follows: https://github.com/bn b-chain/bsc/blob/master/core/vm/lightclient/types.go#L220-L234

DefaultProofRuntime constructor uses the IAVL library to verify Proof:

IAVL code problem

IAVL's Proof verification process, there is a vulnerability in Hash calculation, which causes hackers to add data in Proof, but the added data is not used when calculating Hash. The detailed analysis is as follows:

In the branch where len(pin.Left) is not 0, the pin.Right data is not used to calculate Hash. The hacker used this vulnerability to construct data and added proof.LeftPath[1].Right data, but the data does not participate in Hash calculation. https://github.com/cosmos/iavl/blob/master/proof.go#L79-L93

According to the above analysis, the normal data organization structure is as follows, proof.LeftPath[1].Right is a null value, and the correct Hash is calculated.

  • proof.LeftPath = len(2)
  • proof.LeftPath[0] is a normal data, proof.LeftPath[1].Left is a normal data, proof.LeftPath[1].Right null value
  • proof.InnerNodes = len(0)
  • proof.Leaves = len(1), proof.Leaves[0] is a normal data

Hacker constructs the attack data structure as follows, add proof.LeftPath[1].Right data, and the data does not participate in Hash calculation.

  • proof.LeftPath = len(2)
  • proof.LeftPath[0] is a normal data, proof.LeftPath[1].Left is a normal data, proof.LeftPath[1].Right is a fake data,
  • proof.InnerNodes = len(1), InnerNodes[0]=nil
  • proof.Leaves = len(2), proof.Leaves[0] is a normal data, proof.Leaves[1] is a fake data
  • and proof.LeftPath[1].Right = COMPUTEHASH(proof.Leaves[1])

IAVL's proof verification code is as follows, the main logic is a COMPUTEHASH recursive call. Since lpath.Right also inputs data for the hacker, the data constructed by the hacker can pass the check of bytes.Equal(derivedRoot, lpath.Right) and return the result calculated by the previous round of COMPUTEHASH through proof.Leaves[0]. This result is a normal value, thus bypassing the IAVL's proof verification.

https://github.com/cosmos/iavl/blob/master/proof_range.go#L222-L309

The data constructed by the hacker attack includes IAVL:V and multistore related data. The multistore data is also operated based on IAVL. The principle is the same and no detailed analysis will be performed.

The problem exposed by IAVL Proof this time is that local changes in the data cannot be reflected in the whole, causing errors in the verification. In the Cosmos ecosystem, IBC uses ICS23 to verify data. The difference between ICS23 and IAVL Proof verification is that ICS23 will verify data on the values ​​of all "leaf nodes", and finally the calculated root hash is then verified with the on-chain data. OKC uses ICS23's Prove, so there is no security vulnerability encountered by BNBChain this time.

test verification code

uses hacker attack transaction data, based on BNBChain unit test code, and adds test case based on hacker attack transactions, which can fully reproduce hacker attack transactions. The unit test code uses the iavlMerkleProofValidate.Run interface to verify the input data, which is equivalent to calling a precompiled contract. https://github.com/BananaLF/bsc/blob/bsc-hack/core/vm/contracts_lightclient_test.go#L99-L100

Using hacking of transaction data, the new payload data is constructed as value := []byte("okc test hack”), and modify the corresponding data of proof, that is, modify the data corresponding to proof.LeftPath[1].Right and proof.Leaves[1]. The newly constructed data can pass the okcIavlMerkleProofValidate verification, that is, modify the hacker data and pass the verification. In addition, the following unit test code verifies both the original hacker data and the modified data cases, and the verification is successful, which shows that the following test code successfully reproduced using the vulnerability described in this article. https://github.com/BananaLF/bsc/commit/697c5cd73a755a7c93c0ed6c57d069e17f807958

Event Process

1) Beijing time 2022 At 7:27 on October 6, the hacker used the ChangeNOW service to transfer more than 100 BNBs to the BSC chain as the starting attack fund: xa84f85e1afc3e1b8ed5111ba16e11325f8fc5d6081cb6958becd6a333f6d0d1d

2) Beijing time on October 7, 2022, the hacker called the system RelayerHub contract. x1006 Register and become a relayer: xe1fe5fef26e93e6389910545099303e4fee774427d9e628d2aab80f1b53396d6

3) Hacker used the Bsc cross-chain bridge vulnerability to execute it twice, and a total of 2 million BNBs were stolen from it:

Beijing time October 7, 2022 2:26: https://www.oklink.com/zh-cn/bsc/tx/0xebf83628ba893d35b4 96121fb8201666b8e09f3cbadf0e269162baa72efe3b8b

Beijing time October 7, 2022: 4:43: https://www.oklink.com/zh-cn/bsc/tx/0x05356fd06ce56a9ec5b4eaf9c075abd740cae4c21eab1676440ab5cd2fe5c57a

4) The hacker used Venus' lending service to mortgage 900,000 BNBs and borrowed 5,000 from it 10,000 USDT, 62.5 million BUSD and 35 million USDC.

5) Hackers use Stargate cross-chain bridge to transfer assets to ETH, AVAX, FTM and other networks, with a total of approximately US$90 million in assets transferred.

6) At 6:19 Beijing time on October 7, 2022, Binance suspended the BNBChain chain.

At present, the OKLink multi-chain browser has marked the hacker address of the BNB Chain stolen case (starting from x489A). Regarding the follow-up of the theft, the Ouke Cloud Chain chain guard team will further track the case details and synchronize it in time.