![](https://cdn-images-1.medium.com/max/858/1*_rPrMXsie-AMcaGKJWTX5Q.jpeg)
Receiving Ether
One of the main use cases of the Ethereum blockchain is to be able to transfer ether between accounts. There are two types of accounts: Externally Owned Accounts (EOA) or Contract Accounts.
When it comes to sending ether directly to Contract Accounts, there are two solidity functions that can be used: send() and transfer(). However, there are some requirements that contracts need to follow in order to be able to receive ether via those function calls, namely containing a receive function or a payable fallback function.
Note: The reason I am not mentioning that the receive function needs to be payable, is because it is payable by default, where fallback functions are flexible on the definition.
These are the following possibilities:
- The target contract contains a payable fallback function;
- The target contract contains a receive function;
- The target contract contains either a payable fallback function or a receive function, where if the calldata attribute is empty, the receive function will be executed.
![](https://cdn-images-1.medium.com/max/817/0*MUIpN_dqLqtkLkg_.png)
“If neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through a transaction that does not represent a payable function call and throws an exception.” — Solidity Docs
The following code, illustrates the next challenge: Force. The challenge consists on trying to make the following contract balance greater than zero:
As it can be seen, theres no code at all on this contract. Even the basic receive() and fallback() functions are not present.
Exploitation Steps
![](https://cdn-images-1.medium.com/max/500/0*XGiPvsMECFR0OvfO.jpeg)
As mentioned above, there are requirements on whether a contract account can receive ether or not. However, there are two exceptions that bypass the mentioned possible use cases:
“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.
A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it.” — Solidity Docs
In resume, a contract without the mentioned requirements, can also receive ether as:
- A miner block reward;
- A destination of a selfdestruct() call;
- (And to complement the answer) A transfer of ether to the target contract address, before it was deployed/created.
For this challenge, we are gonna exploit it by:
- Creating a malicious contract with a selfdestruct() call;
- Sending some ether to the malicious contract;
- Trigger the selfdestruct(), which will send the ether to the challenge contract, effectively increasing its balance.
Refer below for the malicious contract code:
Running the Exploit
root@Web3 ❯ brownie run --network sepolia -i pwn.py
Brownie v1.19.3 - Python development framework for Ethereum
EthernautforceProject is the active project.
Running 'scripts/pwn.py::main'...
Transaction sent: 0xc3eaf8d49588eaf63b0a7ed33cc5fc8e9dfdfb5992eb5e5cdbc3f6852417d264
Gas price: 3.731397437 gwei Gas limit: 115787 Nonce: 19
TheForceIsWithYou.constructor confirmed Block: 4108319 Gas used: 105261 (90.91%)
TheForceIsWithYou deployed at: 0xCe9eD838D4eF98E418bC41700aedF60a438eA9e8
[+] Force contract @ 0x5152B250A129b60b8F772cF32E517F4b684b2964 with balance: 0
[+] Deployed Malicious Force contract @ 0xCe9eD838D4eF98E418bC41700aedF60a438eA9e8
[+] Topping up Malicious Force contract with 0.01 ether...
Transaction sent: 0x112212e176a28663fd56e7f04f978cd2fb59a3b65676e7fe54deeffc09888581
Gas price: 3.731397437 gwei Gas limit: 24622 Nonce: 20
Transaction confirmed Block: 4108321 Gas used: 22384 (90.91%)
[+] Activating 'self-destruct' @ Malicious Force...
Transaction sent: 0xc5ab50f538262a50b529a68822d7e0030acf031ec1d4dac11c9407ee1526ee3c
Gas price: 3.076287879 gwei Gas limit: 32217 Nonce: 21
TheForceIsWithYou.forceMoney confirmed Block: 4108328 Gas used: 29289 (90.91%)
[+] Force contract balance: 10000000000000000
Interactive mode enabled. Use quit() to close.
![](https://cdn-images-1.medium.com/max/929/0*kpRlpa0_paxgczf3.png)
Refer to the following code for the full exploit:
References
- https://web3py.readthedocs.io/en/stable/index.html
- https://sepolia.etherscan.io/
- https://ethernaut.openzeppelin.com/
Big props to @the_ethernaut for creating the content.