Ethernaut Lvl 2 Fallout Walkthrough: how simple developer errors become big mistakes
This is a in-depth series around Zeppelin team’s smart contract security puzzles. I’ll give you the direct resources and key concepts you’ll need to solve the puzzles 100% on your own.
This simple level challenges you to claim ownership of a contract by exploiting a simple developer typo.
The Walkthrough
Notice fallout()
is misspelled asfal1out()
, causing the constructor function to become a public function that you can call anytime.
// Simply invoke this function with nominal ether
function Fal1out() public payable {
owner = msg.sender;
allocations[owner] = msg.value;
}
Querying contract.owner()
in your console now shows you as the contract owner!
Real examples of such simple human errors
This seemingly trivial level illustrates how simple errors like typos, have historically resulted in serious problems:
The Rubixi Bug
In the Rubixi incidence, the developer changed the contract’s name from Dynamic Pyramid
to Rubixi
. However, he forgot to rename his constructor function from DynamicPyramid()
to Rubixi()
.
Adversaries were then able to call the now publicly invokable DynamicPyramid()
function to gain control of the contract and transfer its ethers out.
The Hackergold Bug
In the Hackergold incidence, the developer used the assignment operator: =+
instead of the intended+=
as follows:
// do the actual transfer
balances[from] -= value;
balances[to] =+ value;
The bug is that when you specify balances[to] =+ value;
you are actually saying: balances[to] = (positive 1) * value
. Thus, anyone is able to arbitrarily reset someone else’s account balance within the contract scope!
Key Security Takeaways
- Practice test driven development. Recommended: Truffle framework offers built in testing for your next DApp.
- Heed compiler warnings, and make sure you are using the latest compiler version.
- Use security analysis tools, which are usually free and good at finding simple human errors.