This repository has been archived by the owner on Oct 8, 2023. It is now read-only.
ShadowForce - Reentrancy in CrossDomainMessenger#relayMessage #38
Labels
Non-Reward
This issue will not receive a payout
Sponsor Disputed
The sponsor disputed this issue's validity
ShadowForce
high
Reentrancy in CrossDomainMessenger#relayMessage
Summary
Reentrancy in CrossDomainMessenger#relayMessage
Vulnerability Detail
In prev audit, the audit shows there is a way to make the user's withdraw transaction revert by taking the advantage of reentrancy guard.
sherlock-audit/2023-01-optimism-judging#87
The fix this issue, the protocol implements the fix such as the version hash is used to make sure the reentrancy will not happen.
ethereum-optimism/optimism#4919
The protocol does not fully remove the reentrancy protection because if the reentrancy protection is fully removed, the relayed message can be relayed multiple times.
ethereum-optimism/optimism#4919 (comment)
because the message is marked as success or fail after the external call, if there is no reentrancy protection, certainly the invariant that
"cross domain messages should only be able to be successfully relayed once" will not hold.
However, I believe the current reentrancy protection is not sufficient enough to protect from the reentrancy.
I would like to highlight one thing before jumping into the exploit. let us take a look at the version hash schema and relay message function call
and
what is the important parameter when relaying a message?
_target is important
_message is important
_value can be optionally important
let us assume the caller will always supply enough gas so _minGasLimit is not important.
the nonce is used to distinguish the message, therefore if in a two relay message has same target and message calldata, we mentally assume that two call is equal.
This is a two step exploit as well, the user can first prepare two transaction relay message transaction and make sure these two transaction revert.
Then the user toggle the revert flag and call the two relay message that has the same target and call data within one transaction, which leads to reentrancy.
the POC is
basically in the set up, the user prepare two failed transaction and toggle the will revert flag and call
exploit.call => CrossDomainMessager#relayMessage with same target and calldata but different nonce => exploit.call => CrossDomainMessager#relayMessage with same target and calldata but different nonce => transaction complete.
because two transactions has different nonce, the version hash has would be different and bypass the reentrancy protection. user can also use _value and _value + 1 wei in two messages or _minGasLimit and _minGasLimit + 1 wei in two messages to result in the output of different versionHash but still use the same target and message call data.
We are running the test
the output is
The full POC is linked below:
https://drive.google.com/file/d/1rT30Zr9e5HCGxL3yYSK9jbV5VkytokqC/view?usp=sharing
Impact
the impact is severe because using the two-step exploit and intentionally preparing failed revert message, user can use reentrancy to replay message multiple times within one transaction.
Code Snippet
https://github.com/sherlock-audit/2023-03-optimism/blob/main/optimism/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol#L290-L384
Tool used
Manual Review, Foundry POC
Recommendation
We recommend the protocol add more strict reentrancy protection to preserve the invariant that
The text was updated successfully, but these errors were encountered: