DEV Community

wallebach
wallebach

Posted on

Ethernaut level #2 - Fallout

Continue with Ethernaut. So, level #2 is a Fallout challenge. Let's check it out.

Requirements

The following smart contract is provided:

// 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

The goal is to claim ownership of the contract.

Solution

Line #2 already gives us some hints:

pragma solidity ^0.6.0;
Enter fullscreen mode Exit fullscreen mode

An outdated Solidity version is used. Also, a short story on the task page gives us another hint - the solution may be related to constructor.

What is a constructor? It's an optional function which is executed during contract creation and is called only once. This concept is common for the majority of programming languages. Constructor has its own advantages and use cases, but we don't need to focus on them now. Let's check some examples on how constructor is called in Solidity 0.6.0.

A quick review of example smart contract in Solidity 0.6.0 documentation shows us that a method with name constructor() is used for constructor instead of a contract name. In fact, contract name as constructor was deprecated in Solidity 0.4.22, see the official release announcement.

So, Fal1out() can't be a constructor under the given pragma. Moreover, this won't work even in Solidity < 0.4.21, because there is a typo. It must be called Fallout() instead of Fal1out().

Now it's clear that there is nothing special about Fal1out() and unlike the constructor it can be called as many times as we want.

Let's see current contract owner:

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

That's not our address. Time to fix this and pwn the contract. Fal1out() is an ideal candidate to give us the ownership. It's a payable function, so send 1 wei to it:

contract.Fal1out.sendTransaction({value: 1})
Enter fullscreen mode Exit fullscreen mode

Good moment to check the owner once again:

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

Voilà. We've gained access to control of the contract.

Summary

The challenge shows that it's important to understand how special functions like constructors are defined. The definitions can change even between the versions of the same programming language. It is also necessary to pay attention to their correct spelling.


If you like this article, feel free to subscribe to my social media accounts:

https://dev.to/wallebach
https://twitter.com/just_buidl

Top comments (0)