Binance Chain Bridge Exploitation Writeup - Part 2
This is the second part of our analysis on Binance Chain's bridge hack, focus on hacker transactions and exploitation payloads.
by Verichains Team
This is the second part of our analysis on Binance Chain’s bridge hack, focus on hacker transactions and exploitation payloads. This analysis also answers @samczsun's questions in his early tweets, in which he wondered how the attacker's payload was much shorter than his me.
Transaction details
The hacker transaction is at https://bscscan.com/tx/0xebf83628ba893d35b496121fb8201666b8e09f3cbadf0e269162baa72efe3b8b. Decoding the transaction data, we got the following arguments that will be passed to the function handlePackage
of CrossChain.sol
smart contract (link):
0 payload bytes 0x000000000000000000000000000000000000000000000000000000000000000000f870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f100
1 proof bytes 0x0a8d020a066961766c3a76120e00000100380200000000010dd85c1af201f0010aed010a2b0802100318b091c73422200c10f902d266c238a4ca9e26fa9bc36483cd3ebee4e263012f5e7f40c22ee4d20a4d0801100218b091c7342220e4fd47bffd1c06e67edad92b2bf9ca63631978676288a2aa99f95c459436ef632a20da657c1ffb86c684eb3e265361ef0fa4f9dfa670b45f9f91c5eb6ad84b21a4d112001a370a0e0000010038020000000000000002122011056c6919f02d966991c10721684a8d1542e44003f9ffb47032c18995d4ac7f18b091c7341a340a0e00000100380200000000010dd85c12202c3a561458f8527b002b5ec3cab2d308662798d6245d4588a4e6a80ebdfe30ac18010ad4050a0a6d756c746973746f726512036962631ac005be050abb050a110a066f7261636c6512070a0508b891c7340a0f0a046d61696e12070a0508b891c7340a350a08736c617368696e6712290a2708b891c7341220c8ccf341e6e695e7e1cb0ce4bf347eea0cc16947d8b4e934ec400b57c59d6f860a380a0b61746f6d69635f7377617012290a2708b891c734122042d4ecc9468f71a70288a95d46564bfcaf2c9f811051dcc5593dbef152976b010a110a0662726964676512070a0508b891c7340a300a0364657812290a2708b891c73412201773be443c27f61075cecdc050ce22eb4990c54679089e90afdc4e0e88182a230a2f0a02736312290a2708b891c7341220df7a0484b7244f76861b1642cfb7a61d923794bd2e076c8dbd05fc4ee29f3a670a330a06746f6b656e7312290a2708b891c734122064958c2f76fec1fa5d1828296e51264c259fa264f499724795a740f48fc4731b0a320a057374616b6512290a2708b891c734122015d2c302143bdf029d58fe381cc3b54cedf77ecb8834dfc5dc3e1555d68f19ab0a330a06706172616d7312290a2708b891c734122050abddcb7c115123a5a4247613ab39e6ba935a3d4f4b9123c4fedfa0895c040a0a300a0361636312290a2708b891c734122079fb5aecc4a9b87e56231103affa5e515a1bdf3d0366490a73e087980b7f1f260a0e0a0376616c12070a0508b891c7340a300a0369626312290a2708b891c7341220e09159530585455058cf1785f411ea44230f39334e6e0f6a3c54dbf069df2b620a300a03676f7612290a2708b891c7341220db85ddd37470983b14186e975a175dfb0bf301b43de685ced0aef18d28b4e0420a320a05706169727312290a2708b891c7341220a78b556bc9e73d86b4c63ceaf146db71b12ac80e4c10dd0ce6eb09c99b0c7cfe0a360a0974696d655f6c6f636b12290a2708b891c73412204775dbe01d41cab018c21ba5c2af94720e4d7119baf693670e70a40ba2a52143
2 height uint64 110217401
3 packageSequence uint64 17684572
4 channelId uint8 2
Where:
payload
contains information about the cross-chain transfer (of course it did not actually happen) including BSC recipient address and token amount which the attacker has set to his/her own address and 1 million BNB respectively.proof
is an IAVL/Merkle proof that asserts the integrity ofpayload
.height
is (at least) the BC (not BSC) block height at which the transfer occurred. TheappHash
of BC corresponding toheight
will be retrieved for verifyingproof
.packageSequence
acts like a TCP sequence number to assure that packages relayed to BSC can not be replayed and arrive in order.channelId
is routing information that is used to select the next appropriate contract to handle the package payload after its verification succeeds. Here,channelId == 2
indicates a cross-transfer (BC to BSC) package which should be handled by theTokenHub.sol
contract (link).
The way BC to BSC cross-chain communication works is that every-time a package needs to be sent to BSC, a key
will be constructed from packageSequence
and channelId
, and its associated value
, which is essentially the package payload, will be stored in the verifiable key-value store of BC and thus, updating BC appHash
. Later on, the package is relayed to BSC together with proof
that proves the correctness of the corresponding key
-value
pair in BC store. This is basically the light-client technique for cross-chain communication.
Next, we will analyze proof
.
Proof details
proof
essentially contains 2 parts.
The first part regards to the multistore architecture of BC. Basically, BC appHash
is the hash of all its sub-store root hashes, including the one named ibc
(short for Inter-Blockchain Communication) in which the key
-value
pair mentioned earlier is actually stored. proof
carries all the sub-store hashes so ibc
root hash could be verified against appHash
. Compared with a valid proof, the attacker did not change this part.
The second part is about proving that a leaf containing key
-value
does actually exist in ibc
IAVL tree given its root hash. The technique used to forge this part has been described earlier. Please notice that both Left
and Right
fields of Proof.LeftPath[1]
are filled:
Based on LeftPath
, we deduce that the ibc
tree snapshot at BC block height 110217401 looks like this:
And the malicious second part is as follows:
So, the BC block height 110217401 chosen by the attacker is likely for minimizing the proof size as the ibc
tree at that time had only a few nodes. Maybe it helped reduce some gas cost when submitting the malicious transaction, or the attacker just prefers a concise proof over longer ones.
This analysis also answers @samczsun's questions in his early tweets, in which he wondered how the attacker's payload was much shorter. As long as the IAVL tree contains at least 2 leafs, the attack is already feasible. Therefore, the proof could be made short, and the attacker chose to do so.