Ethernaut#7 - Force
Ethernaut #7 - Force
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.
1 | // SPDX-License-Identifier: MIT |
Contract Breakdown
Let us breakdown the contract. Mere looking at it we can see the code consists of a single contract Force compiled with solidity version ^0.8.0. And it is… completely empty. There is literally nothing here except a cute ASCII cat.
There are no functions, no receive function, no fallback function, no payable functions. Nothing. The contract does not accept ether in any traditional way.
Solution
So how do we send ether to a contract that has no way to receive it? Normally, a contract needs a receive or fallback function marked as payable to accept ether. But there is one method that bypasses all of this.
selfdestructis a special EVM opcode that destroys a contract and forcefully sends its remaining ether balance to a designated address. The receiving contract has no say in this. It cannot reject the ether. No fallback function is called, no receive function is triggered.
So our plan is to deploy a contract, fund it with some ether, and then call selfdestruct targeting the Force contract address.
1 | // SPDX-License-Identifier: MIT |
Steps to pass:
- Copy the
HackForcecontract to Remix and compile it. - Deploy it with the Force instance address from Ethernaut as the constructor argument.
- Make sure to send some wei along with the deployment transaction (set a value in the “Value” field on Remix before deploying).
- Upon deployment, the constructor executes,
selfdestructfires, theHackForcecontract is destroyed, and its ether balance is forcefully sent to theForcecontract. - The
Forcecontract now has a balance greater than zero.
Never assume that a contract’s balance will be zero just because it has no payable functions.
selfdestruct(and coinbase transactions from miners) can force ether into any contract. If your contract logic depends onaddress(this).balancebeing a specific value, it can be manipulated.