-
Notifications
You must be signed in to change notification settings - Fork 15
PUSH0 - CREATE2
address collision against an Account will allow complete draining of lending pools
#59
Comments
1 comment(s) were left on this issue during the judging contest. takarez commented:
|
Request PoC to facilitate discussion between sponsor and watson. I believe this is low severity given the extreme unlikeliness of it occuring, with the addition that a insanely huge amount of funds is required to perform this attack without guarantee |
PoC requested from @push0 Requests remaining: 8 |
Hello, thanks for asking. The reason we believe this is a valid HM is the following:
Therefore the likelihood of this attack can only increase as time passes. Complete draining of a pool also cannot be low severity. Essentially by identifying this attack, we have proven the existence of a time bomb, that will allow complete draining of a certain pool from any given chain. We understand that past decisions are not considered a source of truth, however the issue discussion and the external resources should still provide an objective reference to determine this issue's validity. Furthermore let's consider the impact if it were to happen as well. |
@Czar102 I am interested in hearing your opinion here with regards to the previous issue here as well. |
Don't think it is a high, requires a very big upfront cost with no certainty on pay out as attacker. If at some point the attack becomes a possibility, we can still block it. To make it even harder, we are thinking to add the block.timestamp and block.number to the hash. |
Agree that it's not a high, the attack cost makes a strong external condition. Re: mitigations. I don't think pausing the contract or blocking the attack makes sense, the attack would sort of finish in a flash before you know it (and in a shorter duration than a pausing multisig can react). Regarding the fix, adding But since it technically works, there's not really a point in opposing it I suppose. A full fix would involve reworking the account's accounting, which I think is quite complex and may open up more problems. A fix that would still (partially, but should be sufficient) retain the mentioned functionalities could be just using a |
Meant it in the sense that if such an attack occurs we can pause it, assuming we would not be the first victim.
Fair point.
I do like this idea thanks! We can use 32 bits from the tx.origin and 32 bits from a salt. |
The protocol team fixed this issue in PR/commit arcadia-finance/accounts-v2#176. |
CREATE2
address collision against an Account will allow complete draining of lending poolsCREATE2
address collision against an Account will allow complete draining of lending pools
Fix looks good. By using a 32 bit salt the collision is increased from 2^81 to 2^128 dramatically increasing the cost. |
The Lead Senior Watson signed off on the fix. |
PUSH0
high
CREATE2
address collision against an Account will allow complete draining of lending poolsSummary
The factory function
createAccount()
creates a new account contract for the user usingCREATE2
. We show that a meet-in-the-middle attack at finding an address collision against an undeployed account is possible. Furthermore, such an attack allows draining of all funds from the lending pool.Vulnerability Detail
The attack consists of two parts: Finding a collision, and actually draining the lending pool. We describe both here:
PoC: Finding a collision
Note that in
createAccount
,CREATE2
salt is user-supplied, andtx.origin
is technically also user-supplied:The address collision an attacker will need to find are:
Both sets of addresses can be brute-force searched because:
salt
is a user-supplied parameter. By brute-forcing manysalt
values, we have obtained many different (undeployed) wallet accounts for (1).CREATE2
, and the salt is in the attacker's control by definition.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:
The hashrate of the BTC network has reached$6 \times 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.
PoC: Draining the lending pool
Even given EIP-3607 which disables an EOA if a contract is already deployed on top, we show that it's still possible to drain the lending pool entirely given a contract collision.
Assuming the attacker has already found an address collision against an undeployed account, let's say
0xCOLLIDED
. The steps for complete draining of a lending pool are as follow:First tx:
0xCOLLIDED
.0xCOLLIDED
---> attacker wallet} for any token they want.selfdestruct
.selfdestruct
is still possible if the contract was created in the same transaction. The only catch is that all 3 of these steps must be done in one tx.The attacker now has complete control of any funds sent to
0xCOLLIDED
.Second tx:
0xCOLLIDED
.0xCOLLIDED
is now infinitely collateralized.The attacker has stolen all funds from the lending pool.
Coded unit-PoC
While we cannot provide an actual hash collision due to infrastructural constraints, we are able to provide a coded PoC to prove the following two properties of the EVM that would enable this attack:
Here is the PoC, as well as detailed steps to recreate it:
Test
.Test.test()
with a salt of your choice, and record the returned address. The result will be:Test.getAllowance()
for that address will return exactlyAPPROVE_AMOUNT
.Test.getCodeSize()
for that address will return exactly zero.Test.test()
again. The tx will go through, and the result will be:Test.test()
returns the same address as with the first run.Test.getAllowance()
for that address will return twice ofAPPROVE_AMOUNT
.Test.getCodeSize()
for that address will still return zero.The provided PoC has been tested on Remix IDE, on the Remix VM - Mainnet fork environment, as well as testing locally on the Holesky testnet fork, which as of time of writing, has been upgraded with the Dencun hardfork.
Impact
Complete draining of a lending pool if an address collision is found.
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.
For a DeFi lending pool, it is normal for a pool TVL to reach tens or hundreds of millions in USD value (top protocols' TVL are well above the billions). It is then easy to show that such an attack is massively profitable.
Code Snippet
https://github.com/sherlock-audit/2023-12-arcadia/blob/main/accounts-v2/src/Factory.sol#L96-L100
Tool used
Manual Review, Remix IDE
Recommendation
The mitigation method is to prevent controlling over the deployed account address (or at least severely limit that). Some techniques may be:
salt
, as well as do not use the user address as a determining factor for the salt.CREATE
, as opposed toCREATE2
. The contract's address is determined bymsg.sender
(the factory), and the internalnonce
of the factory (for a contract, this is just "how many other contracts it has deployed" plus one).This will prevent brute-forcing of one side of the collision, disabling the$O(2^{81})$ search technique.
The text was updated successfully, but these errors were encountered: