Figure 1: Five Arbitrage Steps in bZx Hack
The details of the attack are as follows:
- Don't blame "Lightning Loan", bZx is attacked by it
- Detailed DeZ protocol bZx hacked twice: What is the attack method and how to defend it?
- DeFi Weekly Selection 丨 bZx Event Reflection: What Does Flash Loan Mean?
- DeFi Trust Crisis: Rethinking the bZx Incident
- Dismantling the bZx event: just another advance transaction
- Defi protocol bZx was attacked twice in one week, highlighting industry concerns
This attack occurred at 2020-02-15 09:38:57 Beijing time (block height # 9484688). Attacker's transaction information can be found on etherscan. This attack process can be divided into the following five steps:
The attacker borrowed 10,000 ETH by calling the dYdX flash loan function in the deployed contract. This part is the basic borrowing function of dYdX, we will not explain further.
Figure 2: Flashloan Borrowing From dYdX
After the first step, the attacker's assets in the following table have no benefits at this time:
Figure 3: WBTC Hoarding From Compound
After this step, we can see that the assets controlled by the attacker have changed, but still no benefit at this time:
Figure 4: Margin Pumping With bZx (and Kyber + Uniswap)
It should be noted that this step has a security check logic implemented inside the contract, but the lock value is not actually verified after the transaction. In other words, this check was not enabled when the attack occurred, and we will detail the issues in this contract later.
After this step, we noticed the following changes regarding hacked assets. However, there is still no profit after this step.
After the WBTC price soared in Uniswap (the price is 61.4 WETH / WBTC), the attacker sold all 112 WBTC borrowed through Compound in the second step to Uniswap and returned the corresponding WETH. In this transaction, the attacker received a total of 6,871.41 ETH in return. After this step, you can see that the attacker has made a lot of profit.
Figure 5: WBTC Dumping With Uniswap
Referring to the average market price of 1WBTC = 38.5WETH (1WETH = 0.025BTC), if an attacker purchases 112 WBTC at the market price, it will take about 4,300 ETH. This 112 WBTC is used to settle Compond's debt and retrieve 5,500 ETH in collateral . The total profit of the attacker is 71 WETH + 5,500 WETH-4,300 ETH = 1,271 ETH, for a total of approximately $ 355,880 (current ETH price $ 280).
Hard core analysis: bZx can avoid risk code logic flaws
According to the previous steps implemented by the attacker in the contract, it can be seen that the core cause of the problem is to call marginTradeFromDeposit () in the third step to borrow 1,300 ETH and add 5 times the leverage to short the ETH / WBTC transaction, so we further review The contract code was found to be an "avoidable arbitrage opportunity", but the logic of the code that can be used to avoid risks did not take effect because of a logical error in the code. The specific code is tracked as follows:
The first is marginTradeFromDeposit () calling _borrowTokenAndUse (). Here, the fourth parameter is true (line 840) because the leveraged transaction is the deposited asset.
In _borrowTokenAndUse (), when amountIsADeposit is true, _getBorrowAmountAndRate () is called and the borrowAmount is stored in sentAmounts  (line 1,348).
On line 1,355, sentAmounts  is set to sentAmounts  and _borrowTokenAndUseFinal () is called on line 1,370
Enter bZxContract's takeOrderFromiToken () function via the IBZx interface.
bZxContract belongs to another contract iTokens_loanOpeningFunctions So we continue to analyze the contract code and find a key logical judgment in the function:
On line 148, bZx actually attempts to use the shouldLiquidate () of the oracle contract to check if the leveraged position is healthy. However, because the first condition (lines 146 to 147) is already true, execution continues and the logical judgment of shouldLiquidate () is ignored.
In fact, the judgment of getCurrentMarginAmount () <= loanOrder.maintenanceMarginAmount is implemented in the shouldLiquidate () of the contract BZxOracle. If shouldLiquidate () is executed, this attack can be effectively avoided.
As mentioned earlier, this is an interesting attack that combines a variety of interesting features such as loans, leveraged transactions, and price increases. This attack is possible because current projects share a design that combines composable liquidity. In particular, 5x leverage trading allows users to borrow a large number of tokens at a relatively low cost, coupled with the liquidity shared between DeFi projects, resulting in transaction prices that are more easily manipulated.