Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EgisSecurity - PositionManager::newPosition() - Using address collision and flash loan, an attacker can drain the entire protocol. #332

Closed
sherlock-admin3 opened this issue Aug 24, 2024 · 1 comment
Labels
Non-Reward This issue will not receive a payout

Comments

@sherlock-admin3
Copy link

sherlock-admin3 commented Aug 24, 2024

EgisSecurity

Medium

PositionManager::newPosition() - Using address collision and flash loan, an attacker can drain the entire protocol.

Summary

This issue takes inspiration from this issue and this issue thus a lot of the information will be taken straight from there.

The PositionManager function newPosition() creates a beacon proxy position contract for the user using CREATE2. We show that a meet-in-the-middle attack at finding an address collision against an undeployed position is possible and it will allow draining 5 entire pools of all their assets.

The attack consists of two parts: Finding a collision, and then borrowing from the pools:

When a new position proxy is deployed we use CREATE2 and a salt which consists of owner and salt, which both are user-supplied values:

// data -> abi.encodePacked(address, bytes32)
        // owner -> [:20] owner to create the position on behalf of
        // salt -> [20:52] create2 salt for position
        address owner = address(bytes20(data[0:20]));
        bytes32 salt = bytes32(data[20:52]);

        // hash salt with owner to mitigate positions being frontrun
        salt = keccak256(abi.encodePacked(owner, salt));
        // create2 a new position as a beacon proxy
        address position = address(new BeaconProxy{ salt: salt }(positionBeacon, ""));

We need to find 2 things:

  1. Undeployed position address
  2. Attacker controlled address

Both can be found in the following way:

  1. Since salt is user-supplied, by brute forcing many salt values we find many undeployed positions.
  2. Can be found the same way, the contract has to be deployed with CREATE2 and the salt is in the attackers control by default.

An attacker can find any single address collision between (1) and (2) with high probability of success using the following meet-in-the-middle technique, a classic brute-force-based attack in cryptography:

  • Brute-force a sufficient number of values of salt $(2^{80})$, pre-compute the resulting position addresses, and efficiently store them e.g. in a Bloom filter data structure.
  • Brute-force contract pre-computation to find a collision with any address within the stored set in step 1.

The feasibility, as well as detailed technique and hardware requirements of finding a collision, are sufficiently described in multiple references:

#1 - Past accepted issue
#2 - Another accepted issue
#3 - Another accepted issue
#3 - EIP-3607, which rationale is this exact attack. The EIP is in final state.
#4 - Blog discussing the attack

The hashrate of the BTC network has reached $6×10^{20}$ hashes per second as of time of writing, taking only just 33 minutes to achieve $2^{80}$ hashes. A fraction of this computing power will still easily find a collision in a reasonably short timeline.

Pulling this off, the attacker can target any 5 debt pools he wishes. For collateral he can simply use a flash loan combined with processBatch to borrow up-to the limit of the health of the position. The only cost for the attacker would be to find the collision and pay his flash loan fees.

An example is provided in Attack Path

Root Cause

Using CREATE2 with user-supplied salt

Internal pre-conditions

None

External pre-conditions

None

Attack Path

Now, all the attacker needs to do is the following:

  1. Deploy the attack contract to the collided address.
  2. Set approvals for all the debt tokens he is going to borrow + the collateral token that he is going to use, to another address.
  3. selfdestruct the contract. Post Cuncun this is still possible if selfdestruct is called in the constructor of the contract, so all the above steps along with this one have to happen in one transaction.
  4. After this deploy the real position to the collided address.
  5. Add an asset as collateral to the position using addAsset, flash loan the asset and transfer it directly to the position.
  6. Borrow as many tokens from as many pools as possible, using process and processBatch up to the maximum that your position health allows.
  7. In the same transaction, use the approved address from step 2 to transfer both the collateral + all the borrowed assets out of the position.
  8. Repay the flash loan + it's fee.
  9. 5 pools can be completely drained of all assets.

Impact

Complete loss of funds of up to 5 pools.

PoC

Mitigation

Do not use a user-supplied salt or use CREATE instead of CREATE2. This will severely limit and make it near impossible to find one part of the collision.

Duplicate of #14

@github-actions github-actions bot closed this as completed Sep 5, 2024
@github-actions github-actions bot added the Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label label Sep 5, 2024
@sherlock-admin4
Copy link
Contributor

1 comment(s) were left on this issue during the judging contest.

z3s commented:

this issue was talked about deeply in makerDAO contest here(https://github.com/sherlock-audit/2024-06-makerdao-endgame-judging/issues/64). with the current hardware its not profitable or feasable for the attacker making it a future related issue which is not considered valid by the sponser

@sherlock-admin4 sherlock-admin4 changed the title Bitter Sandstone Worm - PositionManager::newPosition() - Using address collision and flash loan, an attacker can drain the entire protocol. EgisSecurity - PositionManager::newPosition() - Using address collision and flash loan, an attacker can drain the entire protocol. Sep 15, 2024
@sherlock-admin4 sherlock-admin4 added Non-Reward This issue will not receive a payout and removed Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Sep 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Non-Reward This issue will not receive a payout
Projects
None yet
Development

No branches or pull requests

2 participants