DEV Community

Cover image for Ethernaut - Lvl 2: Fallout
pacelliv
pacelliv

Posted on • Edited on

Ethernaut - Lvl 2: Fallout

Requirements: basic understanding of constructors in Solidity.

The challenge 📄

Claim ownership of the following contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import 'openzeppelin-contracts-06/math/SafeMath.sol';

contract Fallout {

  using SafeMath for uint256;
  mapping (address => uint) allocations;
  address payable public owner;


  /* constructor */
  function Fal1out() public payable {
    owner = msg.sender;
    allocations[owner] = msg.value;
  }

  modifier onlyOwner {
            require(
                msg.sender == owner,
                "caller is not the owner"
            );
            _;
        }

  function allocate() public payable {
    allocations[msg.sender] = allocations[msg.sender].add(msg.value);
  }

  function sendAllocation(address payable allocator) public {
    require(allocations[allocator] > 0);
    allocator.transfer(allocations[allocator]);
  }

  function collectAllocations() public onlyOwner {
    msg.sender.transfer(address(this).balance);
  }

  function allocatorBalance(address allocator) public view returns (uint) {
    return allocations[allocator];
  }
}
Enter fullscreen mode Exit fullscreen mode

Studying Fallout.sol 👩‍🏫👨‍🏫

Similarly to the contract from the previous challenge, Fallout.sol is a fundraiser. People are allowed pledge and unpledge ether whenever they want and the owner of the contract can withdraw funds.

This contract uses a version of Solidity < v0.8.x. This means the contract is prone to underflow and overflow. To protect the arithmetic operations the contract implements the SafeMath library from OpenZeppelin and attaches the functions from this library to the uint256 type.

State Variables:

  • allocations: keeps track of the amount deposited by each allocator.
  • owner: address of the current owner of the contract. This address is marked as payable enabling the account to receive ether from the contract.

Functions:

  • Fal1out: the constructor of the contract. Set msg.sender as owner and the msg.value send during deployment as the allocation for the deployer.
  • allocate: method used to deposit ether in the contrac.
  • sendAllocation: method allocators can use to withdraw their allocation.
  • collectAllocation: callable method by the owner to withdaw the entire balance in the contract.
  • allocatorBalance: reads the amount deposited by allocator.

Hacking Fallout.sol 💣💣

This challenge was a little tricky for me because after inspecting the contract, the Fal1out function with the /* constructor */ comment looked weird to me.

When I started learning Solidity, the language was well beyond v0.8.x and I did not know the syntax to declare a constructor in older versions, specifically before v0.4.22.

From the Solidity docs:

Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. This syntax was deprecated and is not allowed anymore in version 0.5.0.

Fal1out was intended to be the constructor of the contract but due a typo while writing it, the function is never called automatically because it's not recognized as a constructor and so the contract is not initialized at creation time.

Fal1out ended up being compiled as a public function accessible by any EOA to call it and claim the ownership of the contract and to gain access to the balance in the contract.

After that brief explanation, it should be straightforward claiming the ownership of Fallout.

In your dev tools call the Fal1out method:

await contract.Fal1out()
Enter fullscreen mode Exit fullscreen mode

After the transaction is mined, verify you own the contract:

await contract.owner() // should return your address
Enter fullscreen mode Exit fullscreen mode

Conclusion ⚡️

Creating a more robust syntax to declare a constructor is one on the many changes implemented by the core devs to make Solidity a more robust and safe language.

Despite the effort of the core devs, typos can still lead to lose of funds or unusable code, we should always try our best on reading our code before deploying it.

Further reading 🧟‍♀️🧟

Top comments (0)