Platform: Code4rena
Start Date: 13/10/2023
Pot Size: $31,250 USDC
Total HM: 4
Participants: 51
Period: 7 days
Judge: 0xsomeone
Id: 295
League: ETH
Rank: 33/51
Findings: 1
Award: $23.96
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: immeas
Also found by: Alra, Arz, GREY-HAWK-REACH, alexzoid, radev_sw, rvierdiiev, sorrynotsorry
23.9577 USDC - $23.96
Because Brahma is planning to deploy on L2 chains where re-orgs are common like on Polygon there should always be an option to redeploy the safe on the same address so no funds are lost because it is very likely that users will deposit funds there right after deploying their console account.
If a user creates a console account and right after deposits funds there but a reorg happens and the account is not deployed but the funds are sent, the user will have to call deployConsoleAccount()
again with the same params so that the nonce is the same and the address where funds were sent is the same, however take a look at _genNonce()
:
225: bytes32 ownersHash = keccak256(abi.encode(_owners)); 253: function _genNonce(bytes32 _ownersHash, bytes32 _salt) private returns (uint256) { 254: return uint256(keccak256(abi.encodePacked(_ownersHash, ownerSafeCount[_ownersHash]++, _salt, VERSION))); 255: }
The problem is that the ownerSafeCount
can be incremented by anyone because _ownersHash
is the hash of the owners array and not the msg.sender so an attacker can call deployConsoleAccount()
with the same owners array and this will increase the ownerSafeCount
.
So when a re-org happens but the users funds were sent, the attacker will call deployConsoleAccount()
with the same owners array but different salt(so the address is not the same as the one the user deployed) this will increase the ownerSafeCount
and the user will never be able to redeploy on the same address and his funds will be lost because _genNonce()
will now return a different nonce
The user will fail to redeploy to the address where the funds were sent and these funds will be stuck forever.
Add this to DeployConsoleAccount.t.sol
, as you can see the attacker can increase the ownerSafeCount
and the user will fail to deploy on the same address
function testDeployConsoleAccountReorg() public { address[] memory owners = new address[](3); owners[0] = makeAddr("owners[0]"); owners[1] = makeAddr("owners[1]"); owners[2] = makeAddr("owners[2]"); //THE RE-ORG HAPPENS HERE //0x476D9D9309B30f21224a2F4296aB68D0420928ef - this is the address that was deployed but a re-org happened //address _wallet = safeDeployer.deployConsoleAccount(owners, 2, bytes32(0), keccak256("salt")); //THE USER SENDS FUNDS RIGHT AFTER DEPLOYING vm.deal(address(this), 1 ether); (bool success, ) = 0x476D9D9309B30f21224a2F4296aB68D0420928ef.call{value: 1 ether}(""); require(success); //THE ATTACKER SEES THIS AND CALLS deployConsoleAccount WITH THE SAME owners array but different salt/params vm.prank(makeAddr("attacker")); address _attackersWallet = safeDeployer.deployConsoleAccount(owners, 2, bytes32(0), keccak256("differentSaltFromTheOneUsedByUser")); console.log("Attackers wallet(different address from the one deployed by the user):", _attackersWallet); console.log("The ownersSafeCount is now:", safeDeployer.ownerSafeCount(keccak256(abi.encode(owners)))); //THE USER THEN WANTS TO REDEPLOY THINKING HE WILL DEPLOY ON THE SAME ADDRESS address _wallet = safeDeployer.deployConsoleAccount(owners, 2, bytes32(0), keccak256("salt")); console.log("The address of the wallet when the user tries to redeploy:", _wallet); //A COMPLETELY DIFFERENT ADDRESS IS DEPLOYED AND THE FUNDS ARE STUCK IN THE CONTRACT console.log("The balance of the contract where the funds are stuck", 0x476D9D9309B30f21224a2F4296aB68D0420928ef.balance); }
Foundry
The solution here is simple - hash msg.sender
with the owners array so that if a re-org happens only msg.sender
that deployed will be able to redeploy on the same address
bytes32 ownersHash = keccak256(abi.encode(_owners,msg.sender));
Other
#0 - c4-pre-sort
2023-10-22T05:08:16Z
raymondfam marked the issue as low quality report
#1 - c4-pre-sort
2023-10-22T05:08:30Z
raymondfam marked the issue as duplicate of #244
#2 - c4-judge
2023-10-31T00:29:00Z
alex-ppg marked the issue as not a duplicate
#3 - c4-judge
2023-10-31T00:29:08Z
alex-ppg marked the issue as primary issue
#4 - c4-judge
2023-10-31T00:31:56Z
alex-ppg marked the issue as satisfactory
#5 - alex-ppg
2023-10-31T00:34:13Z
Both issues describe different attack vectors arising from the same vulnerability; the nonce of a particular owner-set is tied to their hash and not necessarily to the salt_
used for them.
This is indeed an issue, however, classifying it as "Medium" is an over-statement; funds will not be lost as directly interacting with the Gnosis Safe deployer will still permit those funds to be retrieved.
I did note this particular misbehaviour in #396, indicating that this particular misbehaviour is not solely an issue with chain re-orgs but a general flaw in the way the nonce system of the deployer works.
#6 - c4-judge
2023-10-31T00:34:25Z
alex-ppg changed the severity to QA (Quality Assurance)
#7 - c4-judge
2023-10-31T21:26:35Z
alex-ppg marked the issue as grade-b