You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 positionaddress 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 proxyaddress position =address(new BeaconProxy{ salt: salt }(positionBeacon, ""));
We need to find 2 things:
Undeployed position address
Attacker controlled address
Both can be found in the following way:
Since salt is user-supplied, by brute forcing many salt values we find many undeployed positions.
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:
Deploy the attack contract to the collided address.
Set approvals for all the debt tokens he is going to borrow + the collateral token that he is going to use, to another address.
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.
After this deploy the real position to the collided address.
Add an asset as collateral to the position using addAsset, flash loan the asset and transfer it directly to the position.
Borrow as many tokens from as many pools as possible, using process and processBatch up to the maximum that your position health allows.
In the same transaction, use the approved address from step 2 to transfer both the collateral + all the borrowed assets out of the position.
Repay the flash loan + it's fee.
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.
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
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
functionnewPosition()
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 ofowner
andsalt
, which both are user-supplied values:We need to find 2 things:
Both can be found in the following way:
salt
is user-supplied, by brute forcing manysalt
values we find many undeployed positions.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:
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-suppliedsalt
Internal pre-conditions
None
External pre-conditions
None
Attack Path
Now, all the attacker needs to do is the following:
selfdestruct
the contract. Post Cuncun this is still possible ifselfdestruct
is called in the constructor of the contract, so all the above steps along with this one have to happen in one transaction.addAsset
, flash loan the asset and transfer it directly to the position.process
andprocessBatch
up to the maximum that your position health allows.Impact
Complete loss of funds of up to 5 pools.
PoC
Mitigation
Do not use a user-supplied salt or use
CREATE
instead ofCREATE2
. This will severely limit and make it near impossible to find one part of the collision.Duplicate of #14
The text was updated successfully, but these errors were encountered: