code-423n4 / 2024-05-loop-findings

4 stars 4 forks source link

Attacker can bypass lock to claim any number of token they wanted #63

Closed howlbot-integration[bot] closed 3 months ago

howlbot-integration[bot] commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-05-loop/blob/main/src/PrelaunchPoints.sol#L254-L263

Vulnerability details

Impact

In usual circumstances, to obtain 1 ETH worth of lpETH, a user must lock 1 ETH for a period until it can be claimed. However, due to the incorrect validation in the _validateData function, attackers can deposit only a tiny amount of ERC20 Tokens whitelisted by the contract. Subsequently, by creating a malicious ERC20 token, they inflate the contract's ETH balance. Consequently, the contract mistakenly assumes the attacker has locked a sufficient amount of tokens, thus granting the attacker more lpETH than the locked amount.

This is inherently unfair to regular users.

Proof of Concept

When claim is invoked, it calls the _claim function. If the passed _token is an ERC20 Token, it first checks the passed data using _validateData. Subsequently, it utilizes _fillQuote to perform a UniswapV3 swap to ETH, and finally, it fetches the current contract balance and mints corresponding lpETH to the _receiver.

The _validateData function only checks inputToken and outputToken; it does not validate the tokens in the conversion path.

The attacker's attack path is as follows, assuming the ERC20 Token whitelisted is USDT, and the attacker aims to obtain 1 ETH worth of lpETH:

  1. Create a malicious ERC20 Token, referred to as Evil, with overridden transferFrom function to enable specified transfers.
  2. Create two uniswap pairs: USDT-Evil and Evil-ETH.
  3. The attacker deposits a small amount of USDT using lock, for example, 10wei.
  4. Wait until startClaimDate, then invoke claim with the Uniswap path as USDT-Evil and Evil-ETH.
  5. The contract executes _fillQuote for the conversion, transferring 1 ETH to the contract while passing through Evil.
  6. Upon completion of the swap, the contract checks the current balance, presuming 1 ETH has been obtained, and consequently mints 1 ETH worth of lpETH for the attacker.

It's evident that the attacker completely circumvents the locked quantity restriction, claiming any amount of lpETH without the need to lock a substantial amount of tokens.

Tools Used

manual review

Recommended Mitigation Steps

validate all the swap path of token is in the isTokenAllowed array

Assessed type

Invalid Validation

c4-judge commented 4 months ago

koolexcrypto marked the issue as primary issue

0xd4n1el commented 4 months ago

Upon completion of the swap, the contract checks the current balance, presuming 1 ETH has been obtained, and consequently mints 1 ETH worth of lpETH for the attacker.

We never presume the user will get any amount of ETH, so in this way the user could only loose lpETH but not earn more

c4-judge commented 3 months ago

koolexcrypto marked the issue as unsatisfactory: Insufficient proof