智能合约审计-重入漏洞

简介

当调用外部的合约时,外部合约会接管控制流程,从而可能给自己的数据带来意想不到的修改。2016年6月,以太坊最大众筹项目The DAO被攻击,黑客获得超过350万个以太币。正是由于此陷阱。

原因

调用外部合约,fallback回调函数被多次执行。

复现

很多都是老语法的address.call()的语法了,还有fallback函数,老版本是无名函数,现在已经有专门的fallback()
solidity中有三种可以触发fallback函数的

  • 当外部账户或其他合约向该合约地址发送Ether时,fallback函数会被调用。
  • 当外部账户或其他合约向该合约地址发送Ether,但是内部没有fallback函数时,就会抛出异常,然后将以太币退还给发送方。
  • 当外部账户或其他合约调用了一个该合约中不存在的函数时,fallback函数会被调用。

recipient.send() , recipient.call.value()

测试模拟

pragma solidity ^0.6.0;

contract Victim{  // 受害合约
    
    mapping(address=>uint) public balances;
    
    function deposit() public payable{
        balances[msg.sender] += msg.value;  // 先增加点余额
    }
    
    function testCall(uint _v) public{
        require(balances[msg.sender] >= _v);    // 判断余额是否大于这些,大于1 wei
        (bool sent,) = msg.sender.call{value:1 wei}(""); // 只发送1wei
    }
    
    function getBalances() public view returns(uint _value){
        return address(this).balance;
    }
}

contract Attack{    // 攻击合约
    Victim public _vi;  // 创建一个受害者对象
    constructor(address _VictimAddress) public{
        _vi = Victim(_VictimAddress);   // 受害者合约地址
    }
    
    function send() public payable{
        require(msg.value >= 1 wei);    // msg.value外部传参 自己必须有余额
        // _vi.deposit(value: 1 wei)(); // 0.5.0的语法
        _vi.deposit{value: 50 wei}();    // 0.6.0的语法, 这行代码是传过去钱, 就传50 wei
    }
    
    function attack() public payable{
        _vi.testCall(1 wei);    // 只给我们发送1 wei
    }
    
    function getBalances() public view returns(uint _value){
        return address(this).balance;
    }
    
    // 然后触发callback函数,一直回调
    // 当外部账户或其他合约向该合约地址发送Ether时,fallback函数会被调用
    fallback() external payable{    // 回退函数的修饰符只能是external
        // if(address(_vi).balance>=1 wei){
        //     _vi.testCall(1 wei);    // 如果还有钱 就接着给我发
        // }
    }
}

https://youtu.be/KdP_i-7gRBU
主要是因为其他合约向该合约地址发送Ether时,fallback函数会被调用,然后回调函数里接着调用那个发钱的函数,所以导致一直发钱

漏洞修复

  1. 改成transfer
(ool sent,) = msg.sender.call{value:1 wei}("");改成msg.sender.transfer(1 wei);

智能合约审计-重入漏洞
2. 上一个互斥锁,也就是锁定一个局部变量

    bool internal key ;
    
    modifier check(){
        require(key,"gun");
        key = true;
        _;
        key = false;
    }

智能合约审计-重入漏洞
因为key 默认为false,require(false)会异常,然后!取反 不会异常,然后等_;走完。key又为了false,然后就异常了
智能合约审计-重入漏洞

上一篇:关于 SAP Spartacus CSR fallback 之后,是否仍然会继续进行 SSR 的处理


下一篇:CircuitBreaker断路器Fallback如何获取异常