1

I was working on the Reentrance problem for Ethernaut and I noticed that initiating the attack from the constructor will not work. It seems that the fallback function is not reached even though both calls to donate and withdraw work as expected. Calling withdraw in a separate function seems to work fine but I thought it was a bit odd that the following does not.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Reentrance {
  using SafeMath for uint256;
  mapping(address => uint) public balances;

  function donate(address _to) public payable {
    balances[_to] = balances[_to].add(msg.value);
  }

  function withdraw(uint _amount) public {
    if(balances[msg.sender] >= _amount) {
      (bool result,) = msg.sender.call{value:_amount}("");
      if(result) {
        _amount;
      }
      balances[msg.sender] -= _amount;
    }
  }

  receive() external payable {}
}

contract ReentranceAttack {
    address payable immutable deployer;
    IReentrance reentrance;

    constructor() payable {
        deployer = payable(msg.sender);
        reentrance = IReentrance(0x38fc379647e373dA9bbb1B01B14C0586E77d0D1E);
        uint256 amount = address(this).balance;
        reentrance.donate{value: amount}(address(this));
        reentrance.withdraw(amount);
    }

    // this function is never reached
    fallback() external payable {
        // re-enter withdraw
    }
}

1 Answer 1

1

During construction, a contract has no runtime code. This attack must be done in two transactions. The first deploying the contract, the second initiating the re-entrancy attack.

contract ReentranceAttack {
    address payable immutable deployer;
    IReentrance reentrance;

    constructor() payable {
        deployer = payable(msg.sender);
        reentrance = IReentrance(0x38fc379647e373dA9bbb1B01B14C0586E77d0D1E);
    }

    function init() external {
        uint256 amount = address(this).balance;
        reentrance.donate{value: amount}(address(this));
        reentrance.withdraw(amount);
    }

    fallback() external payable {
        // re-enter withdraw
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.