← notes

Ethernaut level one: a fallback function is a public entry point

Feb 21, 2021

Work the Ethernaut levels rather than read the writeups.

ethernaut/fallback.sol is level one and it teaches the thing most Solidity vulnerability lists describe badly. The contract has a receive function that assigns ownership to whoever sends it a bare transfer, guarded only by having previously contributed. The exploit is two transactions: contribute a tiny amount to satisfy the guard, then send a plain transaction with no data, which lands in the payable fallback and hands you the contract. Then withdraw.

The general lesson is not “do not put ownership changes in a fallback”, which is true and too specific to use. It is that a fallback is a public entry point running on any call the contract does not otherwise match, including calls nobody wrote a function for. Every state change inside one is reachable by paths the author never enumerated, because the author was thinking about functions.

receive and fallback being separate in modern Solidity helps by making the bare-transfer case explicit. This is ^0.6.0, which predates that being as clear as it is now.

Working the levels is genuinely different from reading about them: read, the bug is obvious; sitting in front of the contract without being told which level it is, much less so.