Skip to content
This repository has been archived by the owner on Jan 12, 2025. It is now read-only.

neogranicen - Create2 address collision against a to-be-deployed rewarder allows for complete draining of the rewarder. #662

Closed
sherlock-admin4 opened this issue Jul 15, 2024 · 1 comment
Labels
Excluded Excluded by the judge without consulting the protocol or the senior Non-Reward This issue will not receive a payout

Comments

@sherlock-admin4
Copy link

sherlock-admin4 commented Jul 15, 2024

neogranicen

Medium

Create2 address collision against a to-be-deployed rewarder allows for complete draining of the rewarder.

Summary

An attacker with a pre-computed exhaustive Rainbow table for all the salts that will make him deploy a proxy contract at a certain address from his wallet will be able to front run createRewarder and createBribeRewarder, deploy a proxy that points to an implementation that approves him an infinite amount of reward token for the to-be-deployed rewarder in the address it will be deployed on and then self destruct and let the rewarder get deployed.

When the rewarder receives the rewards to be distributed to the user, an attacker will be able to drain all the rewards.

Vulnerability Detail

createRewarder uses _clone which uses cloneDeterministic function to deploy a new rewarder using create2 and adds some values at the end of its bytecode which are called immutable arguments.

The address for the contract to be deployed using Create2 is determined by the last 20 bytes of the following as mentioned in the eip-1014:
$address = Keccak256(0xff || address || salt || Keccak256(initcode))$

Now in the context of createRewarder the address is going to be the factories address and the salt is going to be calculated using the $(nonce+1)$ and the address of the sender of the transaction as is clear form below:

RewarderFactory.sol#L142>  
bytes32 salt = keccak256(abi.encodePacked(msg.sender, _nonces[msg.sender]++));  

Now for the init code cloneDeterministic provides a bytecode for a Minimal proxy preceded by the address of the implementation and followed by the immutable arguments which are the reward token and the pool id as is shown here:

bytes memory immutableData = abi.encodePacked(token, pid);  

createBribeRewarder uses _cloneBribe with the only difference being that the immutable arguments passed are the reward token and the pool address instead of id

Now we can see if a transaction is submitted an attacker will have access to all the data that will let him to compute the address the rewarder will be created at.

Now an attacker can keep brute force searching until he comes up with an exhaustive Rainbow table of what salt is needed to generate any address that can exist within the 20 bytes domain while having the init code as a proxy and the address as his address.

The feasibility, as well as the detailed technique and hardware requirements for doing so, are sufficiently described in multiple references:

  • 1: A past issue on Sherlock describing this attack.
  • 2: EIP-3607, whose rationale is this exact attack. The EIP is in final state.
  • 3: A blog post discussing the cost (money and time) of this exact attack.

Draining the Rewarder

  • Now the rewarder will be waiting for a transaction for creating a rewarder to come into the memepool and when it does he can compute the address of the to-be-deployed rewarder.
  • He checks his list for the salt that outputs the corresponding wallet
  • He front runs the transaction deploying a proxy and setting an implementation that has a function that lets him approve uint max amount of a token of choice to his address and has self-destruct functionality, which is then called to approve himself max uint amount of the reward token of the to be deployed rewarder and destructs the contract all in one transaction so that self destruct works
  • The rewarder gets deployed, and after some time, rewards to be distributed are sent to it.
  • Once that happens the attacker can use his approval to transfer all the reward tokens to him and by doing so drain all the rewarder

Impact

With the advancement of computing hardware, the cost of an attack has been shown to be just a few million dollars, and that the current Bitcoin network hashrate allows about $2^{80}$ in about half an hour. The cost of the attack may be offsetted with longer brute force time.

Though it might seem absurd for an attacker to spend millions to steal some hundreds of thousands the twist is that once the attacker gets the rainbow list he can keep using it to excute multiple attacks which will make him at the end make a profit, and MagicSea will only be a stepping stone on his process.

Code Snippet

https://github.com/sherlock-audit/2024-06-magicsea/blob/42e799446595c542eff9519353d3becc50cdba63/magicsea-staking/src/MasterchefV2.sol#L488

Tool used

Manual Analysis

Recommendation

Use the original version of ClonesWithImmutableArgs which uses CREATE instead of CREATE2

Refrences

This was inspired by this great finding

@github-actions github-actions bot added the Excluded Excluded by the judge without consulting the protocol or the senior label Jul 21, 2024
@0xSmartContract
Copy link
Collaborator

The feasibility of this attack depends on the attacker being able to brute-force all possible salt values. EIP-3607 has introduced some restrictions on the use of create2 to prevent such attacks, but the feasibility of such an attack in real-world scenarios is still debatable.

@sherlock-admin2 sherlock-admin2 changed the title Quaint Alabaster Alligator - Create2 address collision against a to-be-deployed rewarder allows for complete draining of the rewarder. neogranicen - Create2 address collision against a to-be-deployed rewarder allows for complete draining of the rewarder. Jul 30, 2024
@sherlock-admin2 sherlock-admin2 added the Non-Reward This issue will not receive a payout label Jul 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Excluded Excluded by the judge without consulting the protocol or the senior Non-Reward This issue will not receive a payout
Projects
None yet
Development

No branches or pull requests

3 participants