Back to all stories
Reports
Incident Analysis
HopeLend Incident Analysis
10/22/2023

On October 18, 2023, at 11:48:59 AM (UTC), the lending pool of Hope.money was exploited by an attacker who leveraged a flash loan to attack the protocol. Hope.money comprises the HopeLend lending platform, HopeSwap decentralized exchange, the stablecoin $HOPE, and the governance token $LT to offer a comprehensive suite of decentralized financial services to users. The focal point of this attack was the HopeLend protocol, a decentralized lending platform where users can either provide liquidity or earn income from over-collateralized loans.

CertiK provided security reviews of HopeMoney’s LightDAO. The incident described here was the result of a vulnerability in the HopeLend lending pool, and as such was not within the scope of our audit.

HopeLend Incident Analysis

HopeLend Incident Overview

HopeLend harbored a vulnerability within its lending pool, which became apparent during the process of burning deposit certificates. An issue with incorrect integer division led to the truncation of the decimal point section, and consequently, fewer certificates were destroyed than initially intended. This discrepancy between the expected and actual values proved to be exploitable.

An attacker seized upon this flaw to drain multiple lending pools on Hope.money.

Noteworthy among these was the hETHwBTC lending pool, established 73 days prior, which had no funds. The attacker injected a substantial amount of funds into this lending pool, significantly elevating the discount rate, and consequently was able to drain all other funds within a single block transaction.

A twist in the narrative emerged when it was revealed that the original hacker who exploited the vulnerability did not actually reap the benefits of the exploit. Instead, a front-runner detected the attacker's transaction, mimicked the attack, and successfully profited 527 ETH. Half of the attack’s total proceeds were spent by front-runners to bribe the miners who packaged the blocks.

The primary hacker initiated an attack contract in block 18377039 and invoked the attack contract in block 18377042. Concurrently, the front-runner was monitoring the transactions within the memory pool and replicated the attack contract as a front-runner. The exploit input was executed in the same block 18377042, yet the initial hacker's transaction in block 18377042 failed to execute as it was sequenced behind the front-runner.

hope.money

Fund Tracing

Following the exploit, the front-runner transferred the funds to the address 0x9a9122Ef3C4B33cAe7902EDFCD5F5a486792Bc3A roughly an hour after acquiring the profits.

unnamed - 2023-10-23T195832.294

At 05:30:23 AM (UTC), the Hope.money team engaged with the aforementioned address, granting permission to the front-runner to retain 26ETH (representing a 10% profit) as a bounty. This engagement elicited a response from the front-runner.

unnamed - 2023-10-23T200026.150

After an hour-long dialogue, the remaining funds were securely relocated to a GnosisSafe multi-signature vault.

unnamed - 2023-10-23T200108.406

Prerequisite Technical Knowledge

(HopeLend's lending protocol is a fork of Aave, hence the core business logic concerning vulnerabilities aligns with what's detailed in Aave's white paper.)

When users deposit liquidity into Aave, they anticipate earning income. However, not all loan proceeds are distributed to users. A small fraction of the interest income is allocated to a risk reserve, ensuring a level of protection. The majority of the loan proceeds are, however, disbursed to the liquidity providers, enhancing the incentive to participate.

In managing deposits, Aave employs a discounting mechanism to equate the number of deposits at varying time junctures to the count at the liquidity pool's initiation point. This facilitates a straightforward computation of the sum of principal and interest corresponding to the underlying assets for each share using the formula: amount (share) * index (discount rate).

This process mirrors fund purchasing dynamics. For instance, with an initial net value of 1, a user's investment of $100 procures 100 shares. Suppose the net value escalates to 1.03 over time; a subsequent investment of $100 will yield approximately 97 shares, totaling 197 shares for the user.

Essentially, this is an asset discounting exercise based on the index (net value), aimed at accurate principal and interest summation for the user, employing the current index in balance calculations. For instance, on a second deposit, the accurate sum of principal and interest should be 100 * 1.03 + 100 = 203. Without discounting, the sum after the second deposit erroneously becomes (100+100) * 1.03 = 206. With discounting, the sum is correctly adjusted to (100 + 100 / 1.03) * 1.03 = 103 + 100 = 203, validating the discounting process.

unnamed - 2023-10-23T200210.911

Attack Flow

0x25126F207Db7dC427415eA640ce0187767403907 (hETHWBTC pool) 0x5a63e21ebded06dbfcb7271fbcef13c9f0844e74 (Attack Contract)

1. Initial Flash Loan and Collateralization:

  • The attacker started by borrowing 2300 WBTC from Aave Flash Loan, pledging 2000 WBTC to HopeLend subsequently.
  • The funds were transferred to HopeLend's hETHwBTC contract (0x251...907), securing 2000 hETHWBTC in return.

unnamed - 2023-10-23T200259.644

2. Manipulating the Initial Discount Rate (liquidityIndex) via Empty Lending Pool:

  • The attacker borrowed 2000 WBTC through a flash loan from HopeLend.

unnamed - 2023-10-23T200525.015

  • At this stage, the exchange rate stood at 1 hETHWBTC = 1 WBTC, unaffected by the deposit and withdrawal operations, as changes in the rate occur only upon earning interest.

3. Discount Rate Manipulation:

  • The attacker transferred the 2000 WBTC directly to HopeLend's hETHwBTC contract (0x251...907), not as a loan repayment.
  • They then withdrew nearly all the WBTC (1999.999...), necessitating the transfer back of WBTC to replenish pool assets.
  • Eventually, only a minuscule unit (1e-8) of hETHwBTC was retained by the attacker, essential for maintaining a non-zero discount rate (liquidityIndex) during calculations.

4. Replenishment and Flash Loan Repayment:

  • Having destroyed most of the hETHwBTC in the preceding steps, the returned wBTC, along with remaining wBTC from the initial flash loan, was used to settle the HopeLend flash loan, amounting to a total repayment of 2001.8 WBTC (inclusive of 1.8 wBTC interest).

5. Amplifying the Discount Rate:

  • The attacker repeatedly borrowed 2000 wBTC from HopeLend via flash loans, each time returning an additional 1.8 WBTC, thus incrementing the liquidityIndex by 126,000,000.

unnamed - 2023-10-23T200957.028

unnamed - 2023-10-23T201637.894

- After repeating this process 60 times, the `liquidityIndex` soared to 7,560,000,001, elevating the discounted value of the attacker's smallest hEthWBTC unit to 75.6WBTC (~$2.14M).

6. Draining Other Lending Pools:

  • Utilizing 1 minimum unit of hETHwBTC as collateral, the attacker borrowed assets from HopeLend's other five token pools.

  • Acquired assets included 175.4 WETH, 145,522.220985 USDT, 123,406 USDC, 844,282 HOPE, and 220,617 stHOPE, which were later converted into WBTC and WETH via Uniswap.

unnamed - 2023-10-23T201753.112

7. Cashing Out:

  • To retrieve the wBTC, the attacker deployed an additional attack contract: 0x5a63e21ebded06dbfcb7271fbcef13c9f0844e74, invoking the withdrawAllBtc() function.

unnamed - 2023-10-23T202147.033

  • The procedure entailed depositing 151.20000002 wBTC, acquiring 2 minimum units of hEthwBTC based on the prevailing liquidityIndex. Subsequently, 113.4 wBTC were withdrawn, necessitating the destruction of 1.9999999998 minimum units of hETHwBTC. However, due to the div function's precision, only one minimum unit of hETHwBTC was destroyed, exposing an exploitable vulnerability. This allowed the hacker to retain 1 minimum unit of hETHwBTC, capitalizing on the integer division error to cash out.

Why the Attacker Could Borrow From Other Pools

When borrowing or withdrawing deposits, the lending contract will check the user's mortgage asset status to ensure that the loan does not exceed the mortgage. Since the discount rate has been manipulated by hackers before and the discount rate will be included in the mortgage value calculation with the normalizedIncome multiplier, the mortgage value of one unit of hETHwBTC in their hand was as high as 75.6 WBTC.

unnamed - 2023-10-23T202256.515

unnamed - 2023-10-23T202434.998

Discount Rate (liquidityIndex) Manipulation

The attacker manipulated the discount rate through a series of complex operations:

  1. The attacker directly transfers the acquired 2,000 WBTC to HopeLend's hEthWbtc contract (0x251...907). This action does not constitute a loan repayment.
  2. Subsequently, the attacker withdraws almost all the WBTC (1999.999...) pledged earlier (1999.999...), making the previous transfer of WBTC imperative to restore the pool's assets.
  3. Ultimately, the attacker retains only the smallest unit (1e-8) of hETHwBTC. A complete withdrawal isn't feasible here, as a marginal amount needs to be retained. The discount rate (liquidityIndex) computation is based on the aggregate of existing and new values. A complete withdrawal would reset the discount rate to zero, disrupting the pool's proportionality.
  4. The majority of hETHwBTC was destroyed in the preceding step, and the returned wBTC was combined with the leftover wBTC from the initial flash loan. The flash loan acquired from the HopeLend pool was settled, totaling a repayment of 2001.8 WBTC (inclusive of 1.8 wBTC interest).
  5. These operations destroyed most of the hETHwBTC, preserving just 1 minimum unit (1e-8) of hETHwBTC in the attacker's account. Consequently, the overall quantity of hETHwBTC diminished, while 2001.8 wBTC remained in the lending pool. At this time, the discount rate (liquidityIndex) increased to126,000,000.

The Vulnerability

unnamed - 2023-10-23T202535.897

The hEthWBTC contract invokes the high-precision division function rayDiv.

unnamed - 2023-10-23T202656.191

Within this function, the variables are assigned as follows:

  • a = 11340000000 (wBTC intended for withdrawal),
  • b = 7560000001000000000000000009655610336 (discount rate).

While the precise calculation (a*1e27+b/2)/b results in 1.9999999998, Solidity's inherent div function truncates this to 1, effectively rendering it as 11340000000 / 7560000001. The decimals are discarded post-division. The attacker's contract 0x5a63 proceeded to deposit 75.60000001WBTC and acquired exactly 1 minimum unit of hETHwBTC, hence maintaining 2 minimum units of hETHwBTC.

In this revolving cycle of withdrawing 113.4 wBTC and depositing 75.60 wBTC, the attacker manages to generate 37.8 wBTC each time.

After 58 cycles, the attacker retrieved all initially invested wBTC and successfully repaid the Aave flash loan.

Conclusion

Given that the hETHwBTC lending pool was uninitialized, the attacker could easily manipulate the liquidityIndex. Once the withdrawal rate was significantly heightened as a divisor, the truncation error inherent in integer division facilitated withdrawal of funds within a single block.

In a secure lending pool, a minor increase in loan interest doesn't substantially elevate the discount rate since the pool already possesses liquidity.