#6: Hundred Finance Incident: Catalyzing the Wave of Precision-Related Exploits in Vulnerable Forked Protocols

On April 16th, 2023, Hundred Finance, a Compound V2 fork, was attacked, leading to a loss of about $7.4 million.

#6: Hundred Finance Incident: Catalyzing the Wave of Precision-Related Exploits in Vulnerable Forked Protocols

On April 16th, 2023, Hundred Finance, a Compound V2 fork, was attacked, leading to a loss of about $7.4 million. The attack involved two main issues:

  • A precision loss issue (an incorrect rounding issue);
  • A empty markets, which allowed the hacker to manipulate the exchangeRate.

Compound V2, the most forked lending protocol according to DeFiLlama, boasts over 100 forks. Audited by OpenZeppelin and proven in battle, its contracts are deemed secure. Yet, the Hundred Finance attack highlighted how precision loss, especially in low liquidity, can critically affect DeFi protocol security, triggering a wave of similar exploits across notable forks like Midas and Radiant.

For a deeper understanding, you are encouraged to consult the full analysis. Below, we provide a succinct introduction to this incident, highlighting it as one of the top ten security incidents of 2023.

Background

Overview of Hundred Finance

Hundred Finance is a fork of Compound v2 that operates across multiple mainnets, utilizing Chainlink oracles. Unlike traditional finance lending practices, DeFi lending protocols like Compound and Aave do not allow for over-collateralized borrowing. Simply put, if you deposit $100 worth of Token A, you can only borrow assets worth less than $100. According to the risk control coefficients of most protocols, this ratio typically ranges from 50% to 80%.

For lending protocols, common attack methods include price manipulation and reentrancy. Interestingly, Hundred Finance had previously experienced a reentrancy attack in March 2022, but this incident created a new attack vector.

hToken

Lending protocols that fork from Compound and Aave create a corresponding accounting token for each underlying token (collateral). For Hundred Finance:

  • USDC corresponds to hUSDC
  • WBTC corresponds to hWBTC

The exchange rate between underlying token and hToken is referred to the exchangeRate.

  • When depositing assets, users should call the mint() of the hToken.
  • When withdraw assets, user should call the redeem() of the hToken.

exchangeRate

The following is the formula for calculating the exchangeRate:

Where:

  • getCash(): The amount of underlying token balance owned by this hToken contract. This is a key parameter that can be manipulated. Please remember this.
  • totalBorrows(): The amount of underlying token currently loaned out by the market, and the amount upon which interest is accumulated to suppliers of the market.
  • totalReserves(): Reserves are an accounting entry in each hToken contract that represents a portion of historical interest set aside as cash which can be withdrawn or transferred through the protocol’s governance.
  • totalSupply(): The number of tokens currently in circulation in this hToken market.

Note: The exchangeRate between a hToken and the underlying asset e.g. (dai vs hDai or eth vs hEth) begins at 0.020 and increases at a rate equal to the compounding market interest rate.

Liquidation

To prevent bad debt, lending protocols allow any user to liquidate another user's debt. Let's use the following example to illustrate:

  1. Alice deposits BTC worth $100 and borrows ETH worth $70.
  2. If the price of ETH rises or the price of BTC falls, Alice's assets may reach the liquidation threshold.
  3. Bob can use a certain amount of ETH to liquidate Alice's BTC, bringing Alice's debt back to a healthy level to ensure the safety of the protocol's funds (the protocol rewards users who initiate liquidation).

Liquidation is not the focus of this attack, but it was involved in the attack. Here, we only need to know that any user can liquidate another user's debt with one type of Token, which will reduce the corresponding hToken.

The Vulnerability

Precision Loss Issue

The hacker makes that when collateral is withdrawn through redeem(), the calculation for the amount of hToken to be deducted results in 1.99999992 (very close to 2 but less than 2). When converting to an integer in truncate(), the use of rounding down leads to a final result as 1.

exchangeRate

The calculation of the exchangeRate, as previously introduced, involves getCash(), which refers to the amount of underlying balance owned by the hToken contract. By directly transferring underlying tokens into the contract (without mint, just transferring), the hacker can manipulate the exchangeRate. However, it's important to note that this exchangeRate issue alone does not compromise security of the protocol; Hackers cannot profit from it in isolation. In the context of this attack, it was primarily exploited to amplify the hacker's gains, allowing them to rapidly deplete the pool. Otherwise, the attack shifts from a single, decisive strike to a series of minor stabs, requiring numerous iterations to have a significant impact.

To be brief, the precision loss is key issue in this attack.

The Attack Process

Here is the attack transaction, and we will now use the Phalcon Explorer to analyze this complex transaction.

Transaction: 0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451

  1. Borrow 500 WBTC from Aave V3 through a Flashloan.

  2. Redeem all the previously acquired hWBTC, reset hWBTC's totalSupply to 0.

The objective before is prepare reserve funds using a flashloan and to reset hWBTC as a new market.

  1. Create the second attack contract (hereafter referred to as Attack Contract 2) and transfer all WBTC (500.30063816 WBTC) to Attack Contract 2.

  2. Mint() hWBTC using 4 WBTC to produce 200 hWBTC.

  3. Redeem() 199.99999998 hWBTC, leaving the hWBTC total at 0.00000002 (2 wei hWBTC).

  4. Transfers all WBTC (500.30063816 WBTC) into hWBTC. Note, direct transfers do not increase hWBTC; it can be seen as donating WBTC to the pool. The main purpose of this step is to manipulate the exchangeRate mentioned earlier. At this point, hWBTC's totalSupply remains at 2 wei hWBTC, but there are now 500.30064194 WBTC, making the exchangeRate hundreds of times the original.

  5. Borrow 1021 Ether from the hETH market.

  6. Redeem() 50030063815 WBTC, where, after calculation, 1.9999992 hBTC should be deducted, but due to precision loss, only 1 hBTC is deducted, creating a significant precision loss (nearly 50%). At this point, the hacker has 500 WBTC + 1021 Ether, successfully profiting 1021 Ether.

  7. The attacker liquidate() the remaining hWBTC, resetting its totalSupply to 0, in preparation for continuing attacks on other markets. Given that almost all WBTC within hWBTC has been withdrawn, the hacker manages this with just 0.000002 Ether.

  8. Continue to attack other markets, draining the entire protocol.

  9. Repay the Flashloan to Aave.

Security Recommendations

Mitigations for Lending Protocol

This issue is prevalent, particularly for forks of Compound and Aave. A proactive approach involves, when launching new markets, minting some accounting token to ensure the totalSupply never goes to 0.

Mitigations for Precision Loss Issue

To better circumvent the series of issues due to precision loss, setting a minimum value is an effective method in practice. This strategy helps to avoid the significant impact caused by precision loss when dealing with very small values.

Read other articles in this series:

Sign up for the latest updates