My solution for my 6th ethernaut challenge:
https://ethernaut.openzeppelin.com/level/0x22699e6AdD7159C3C385bf4d7e1C647ddB3a99ea
The code for the contract here is very simple. The contract does not have a receive or fallback function, so it does not intend to receive any ether. The challenge here is to send some ether to the contract unexpectedly.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Force {/*
MEOW ?
/\_/\ /
____/ o o \
/~____ =ø= /
(______)__m_m)
*/}
I was not familiar with any ways of sending ether to a contract without through the fallback methods. In fact, I tried sending funds directly to the contract address with metamask but the transaction failed.
So, to the docs! Under the section for receive, there is a handy warning about receiving funds
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.
If the contract address receives a miner block reward or if it is the destination of a selfdestruct, it will always receive that ether even without a fallback function. I was not aware of selfdestruct, so I did some more digging.
selfdestructsends all remaining Ether stored in the contract to a designated address.
This looks very handy. If I can create a new contract, I should be able to use selfdestruct to send the ether in the contract to the one I am interested in attacking
I created a new solidity contract to attack the contract of interest
contract ForceSendEther {
address payable recepient;
constructor(address payable _recepient) {
recepient = _recepient;
}
receive () external payable {}
function attack() public {
selfdestruct(recepient);
}
}
I now deployed this contract and sent a little bit of eth to it. Finally, calling the attack function on my contract, I self destruct it and the EVM sends all the eth in the contract to the recipient. Interestingly, the ether shows up in the contract, but there were no transactions indicating it did
https://rinkeby.etherscan.io/address/0xFe58aDE3a009C593cF5621dB793f5dBEd403523D
I think this has an interesting implication that there is no paper trail when ether is sent to a contract this way.
Even without a fallback function, contract A can still be forced to receive ether if contract B
selfdestruct’s and sets contract A as the recipientThere is no visible transaction in etherscan indicating that ether was deposited. Rather, the ether just shows up in the new contract. I will investigate this further
