At 9:34PM UTC on January 27th, 2022, an attacker began their exploit of Qubit Finance’s Ethereum-BSC bridge. This exploit ended up netting them 77,162 qXETH ($185 million), which they then used to borrow and convert 15,688 wETH ($37.6 million), 767 BTC-B ($28.5 million), approximately $9.5 million in various stablecoins, and ~$5 million in CAKE, BUNNY, and MDX.
At $80 million TVL (Total Value Lost), this is by far the largest exploit of 2022 to date.
In this post-mortem analysis, we’ll break down exactly how it happened.
The attacker’s wallet, visualized using Skytrace
Who’s the Target?
Qubit Finance bills themselves as “a decentralized money market platform that takes advantage of the speed, automation, and security of the blockchain to connect lenders and borrowers efficiently and securely.”
In addition to lending and borrowing services, Qubit Finance operates an Ethereum-BSC bridge. It was this bridge that was the target of the exploit.
A bridge in crypto is a piece of infrastructure that connects two (or more) blockchains. In the case of Qubit Finance’s bridge, you deposit your ERC-20 tokens to the bridge and receive BEP-20 tokens in return, which you are then free to go and use on Binance Smart Chain.
How Did This Happen?
For the non-technical readers, essentially what the attacker did is take advantage of a logical error in Qubit Finance’s code that allowed them to input malicious data and withdraw tokens on Binance Smart Chain when none were deposited on Ethereum.
All this, despite several failsafes.
For the technically-minded, see the exact attack flow below:
1.The attacker called the deposit() function in the QBridge contract without any ETH attached in this transaction.
-In the function call, the attacker inputted malicious data
-The data parameter should specify how many ETH has been deposited and then emit an event reflecting this amount
-On BSC, a certain amount of Qubit xETH is minted according to how many ETH were deposited into the Ethereum bridge
2. According to the deposit logic of QBridge contract, it invokes IQBridgeHandler(handler).deposit(), which would further verify the data injected in the QBridge.deposit() function call
3. In the QBridgeHandler contract, tokenAddress in L127 is address(0). There are 3 statements to ensure the correctness of the data parameter. However, none of them failed
-Line 128: As address(0) is whitelisted, Line 128 would be bypassed
-Line 134: As the amount is 190 ETH (bigger than minAmounts), Line 134 would be bypassed
-Line 135: As address(0) is an externally owned address (EOA), the low level call from safeTransferFrom() would return successfully
4. Finally, the attacker successfully invoked the deposit() function with malicious input data yet actually deposited 0 ETH
One of the root causes of the vulnerability was the fact that tokenAddress.safeTransferFrom() does not revert when the tokenAddress is the zero (null) address (0x0…000).
Our analysts found two further smart contract code logic errors:
-Depositing ETH and depositing ERC20 tokens use the same deposit event
-safeTranferFrom does not revert when the token address is an externally owned account (EOA)
What Have We Learned?
As of the time of publication, the attacker’s address still holds approximately $80 million of stolen assets.
The exploit of a cross-chain bridge highlights two things:
- The importance of cross-chain bridges that facilitate interoperability between blockchains
- The importance of the security of these bridges
As we move from an Ethereum-dominant world to a truly multi-chain world, bridges will only become more important. People need to move funds from one blockchain to another, but they need to do so in ways that are not susceptible to hackers who can steal more than $80 million dollars.