sherlock-audit / 2024-06-magicsea-judging

8 stars 5 forks source link

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

Closed sherlock-admin4 closed 3 months ago

sherlock-admin4 commented 3 months ago

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:

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

0xSmartContract commented 3 months ago

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.