Cheese Bank Incident: Root Cause Analysis

In this blog, we analyze a Cheese Bank hack that occurred at 19:22:21 PM +UTC, Nov-6–2020. This hack was discovered while we review evil-will flashloans. This particular hack drains $3.3 million of USDC/USDT/DAI from Cheese Bank by exploiting a bug in its way to measure asset price from an AMM-based oracle. In the following, we elaborate the technical details.

Summary

Background

In this month (of Nov. 2020), PeckShield researchers have reported two flashloan attacks, i.e., Akropolis and Value DeFi. In the string of attacks, we have seen malicious actors use flashloans to instantaneously borrow, swap, deposit and again borrow large numbers of tokens so they can artificially manipulate the price of a specific token on a single exchange (e.g., Uniswap, Curve). This sequence is essentially the foot in the door, allowing the attacker to then exploit that exchange’s anomalous pricing. In this blog post, we elaborate a recent incident happened to Cheese Bank — a decentralized autonomous digital bank based on a decentralized protocol on Ethereum.

Details

The Hack Walk-through

  • Step 1: Take a flashloan of 21k ETH from dYdX
Step 1: dYdX Flashloan of 21k ETH
  • Step 2: Swap 50 ETH to 107k CHEESE at UniswapV2
Step 2: Swap 50 ETH to 107k CHEESE at UniswapV2
  • Step 3: Add 107k CHEESE and corresponding 78 ETH into the liquidity pool at UniswapV2 and gets UNI_V2 LP tokens back.
Step 3: addLiquidity(107k CHEESE, 78 ETH) at UniswapV2
  • Step 4: Mint sUSD_V2 tokens with all LP tokens got from Step 3. This allows the exploit contract to use those LP tokens as collaterals for borrowing crypto assets from Cheese Bank.
Step 4: Mint sUSD_V2 Tokens with UNI_V2 LP Tokens
  • Step 5: Raise the CHEESE price at UniswapV2 by swapping 20k ETH to 288k CHEESE, which makes the UNI_V2 LP tokens more valuable as collaterals in Cheese Bank. This is the crucial step in this incident since the Cheese Bank uses the amount of WETH in a liquidity pool to estimate the price of the corresponding LP token. The manipulated UNI_V2-CHEESE-ETH pool (with 20k+ WETH) allows the bad actor to drain all the USDC, USDT, and DAI withheld by Cheese Bank by legit borrow() calls.
Step 5: Raise CHEESE Price by Swapping 20k ETH to 288k CHEESE at UniswapV2
  • Step 6: Refresh the price feeds of Cheese Bank. The hacker intentionally invokes the CheesePriceOracle::refresh() function to refresh the price of UNI_V2-CHEESE-ETH LP token which is derived from the amount of WETH in the liquidity pool and the ETH price derived from UNI_V2-USDT-ETH pool. Specifically, the CheesePriceOracle::fetchLPAnhorPrice() function gets the wEthBalance of UNI_V2-CHEESE-ETH contract. With the passed in ethPrice, the totalValue is derived by wEthBalance x 2 x ethPrice. Therefore, the unit price of UNI_V2-CHEESE-ETH LP token is computed by totalValue / totalSupply of LP tokens. It means if a bad actor could somehow increase the amount of WETH in a pool (e.g., addLiquidity() with flashloan ether), the price of the LP token would be increased.
Step 6: Refresh the price Cheese Bank
CheesePriceOracle::fetchLPAnchorPrice()
  • Step 7: Drain the USDC, USDT, DAI withheld by Cheese Bank by borrow() calls.
Step 7: Borrow 2m USDC from Cheese Bank

Besides the 2m USDC, 1.23m USDT and 87k DAI are borrow()ed from Cheese Bank. Note that the hacker actually checks the balance before doing borrow(). As shown in the following screenshot from https://oko.palkeo.com/, the exact balance of USDC/USDT/DAI are borrow()ed by the exploit contract.

Drain the USDC/USDT/DAI
  • Step 8: Swap 288k CHEESE back to 19.98k ETH at UniswapV2. Now, the bad actor harvests $3.3m equivalent USDC, USDT, and DAI. She needs to pay the 21k ETH flashloan back to dYdX with the assets in her pocket. The first choice is the really valuable 288k CHEESE which fills in \~20k ETH.
  • Step 9: Swap 58k USDC to 132 ETH at UniswapV2. Since there’re some ether consumed in previous steps (e.g., fees paid to Uniswap), the bad actor needs to buy some more ether with USDC.
  • Step 10: Collect the hacked assets into 0x02b7.
Step 10: Collect the Hacked Assets
  • Step 11: Return 21k ETH flashloan to dYdX
Step 11: Return the 21k ETH Flashloan to dYdX

Aftermath

About Us

A Blockchain Security Company (https://peckshield.com)