Reentrancy attack with withdraw amount

148 views Asked by At

I've been working on different ways to perform reentrancy attacks and there is one case which I have still not seen any working example on the internet. In the book Mastering Ethereum, the reentrancy attack is explained with a contract where the function withdraw(uint amount) takes the input amount. The version on Solidity has been updated a lot since then and whenever I try to perform a similar attack, it does not work. It works whenever the function withdraw() takes no arguments and it also works when using older versions.

Could anyone provide an example of a reentrancy attack where the target contract takes the withdraw amount as input?

Thank you!


1

There are 1 answers

0
Jeffrey On

Let's say you have 1 ether in the contract, and the contract has a total of 10 ether. You're trying to steal all 10 ether with re-entrancy, but that necessarily means the variable tracking your balance must underflow to the equivalent of uint256(-9) ether -- you're trying to withdraw 1 ether 10 times.. This will cause a revert in Solidity 0.8.0 or higher, since it has built in under/overflow protection. If you want it to work in 0.8.0, you have to wrap the balance reduction line with unchecked.

This code is still vulnerable to re-entrancy in 0.8.0, but only because it sets the balance to zero, and can't underflow


mapping(address => uint256) public balance;

function deposit() external payable {
  balance[msg.sender] += msg.value;
}

function withdraw() external {
  msg.sender.call{value: balance[msg.sender]}(""); // re-entrancy
  balance[msg.sender] == 0; // cannot underflow
}

function withdrawV2(uint256 value) external {
  require(value <= balance[msg.sender], "you don't have that much"); // not that this does anything...
  msg.sender.call{value: balance[msg.sender]}("");
  unchecked { // now it can underflow
    balance[msg.sender] -= value;
  }
}