Force - Level 07

Stefan Alfbo - Aug 14 '23 - - Dev Community

Problem statement

Some contracts will simply not take your money ¯_(ツ)_/¯

The goal of this level is to make the balance of the contract greater than zero.

Things that might help:

  • Fallback methods
  • Sometimes the best way to attack a contract is with another contract.
  • See the "?" page above, section "Beyond the console"
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Force {/*

                   MEOW ?
         /\_/\   /
    ____/ o o \
  /~____  =ø= /
 (______)__m_m)

*/}
Enter fullscreen mode Exit fullscreen mode

Solution

Start with creating a new contract for the current level by clicking on the button, Get new instance. Remember to have enough eth in the connected wallet and that it's connected to the Sepolia network.

Open up the developer tool in your browser (F12) and in the console check the address of the contract.

contract.address
Enter fullscreen mode Exit fullscreen mode

Open a new tab in your browser (Ctrl+t) and go to Remix.

In the file explorer, create a new file and name it HackTheForce.sol, and paste this code to the contract.

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

contract HackTheForce {

    function hack(address _address) public payable {
        selfdestruct(payable(_address));
    }
}
Enter fullscreen mode Exit fullscreen mode

Compile the contract and deploy it to the Sepolia network. Make sure the you select the correct environment, Injected Provider - MetaMask

Environment

And make sure that the correct contract is selected before clicking the Deploy button. Sign the transaction with your MetaMask wallet.

Take the address from step one and paste it into the address field for the hack function.

transact button

We also need to add some Wei to send to the function. Do this by setting a value in the field above the contract.

Value

Now click the transact button and sign the transaction, wait for the transaction to be accepted.

Now jump back to the challenge page and open up the developer tool in your browser (F12), and in the console check the balance of the contract.

await getBalance(contract.address)
Enter fullscreen mode Exit fullscreen mode

If the balance is more than zero, finish up the challenge by clicking on the button, Submit instance, to commit and update the progress on the ethernaut contract.

Explanation

Clearly we need to send eth to a contract that has neither a receive or a payable fallback function.

If we try to send eth anyway the transaction will throw an exception.

However if we study the Solidity docs we can find this interesting warning.

A contract without a receive Ether function can receive Ether as a recipient of a coinbase transaction (aka miner block reward) or as a destination of a selfdestruct.

Here it seems that it's most feasible to try the selfdestruct method of the two possible ways to send the contract some ether.

Note: The selfdestruct got deprecated in Solidity version 0.8.18 and the reasons can be found in EIP-4758.

By using this tip, Sometimes the best way to attack a contract is with another contract, that was given in the instruction, we can create a contract that is using the selfdestruct operation.

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

contract HackTheForce {

    function hack(address _address) public payable {
        selfdestruct(payable(_address));
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see we are using an older version of solidity by using pragma solidity ^0.8.17; because of the use of the deprecated selfdestruct operation.

The function hack is a public payable function so that we can send some eth to transfer to the contract we are attacking.

The function body is using the selfdestruct to send all the funds of the HackTheForce contract to the given address.

This is how the signature of the operation is described in the documentation.

selfdestruct(address payable recipient): destroy the current contract, sending its funds to the given address

The signature is forcing us to cast the address with the help of payable, selfdestruct(payable(_address));.

With all this in place we are able to hack the contract.

The take away from the level author.

Take away

Resources

  • Force - This challenge
  • Remix - Web based IDE for Solidity
  • Solidity - Solidity documentation
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .