泄露资金的合约

合约有多种导致资金泄露的方式。例如,合约可能将资金转给非指定的收款人;或者将超额资金转给合法收款人等。

以下展示了对DAO合约的攻击,该攻击者借此盗取了6000万美元。大家可以观察到,该合约有一个状态变量shares。将状态变量视为可由任何函数访问的全局变量。

  • shares维护用户地址和相应份额之间的映射。
  • 股东可以调用withdraw()来提取他们的份额。
contract UnsafeContract1{

    // Mapping of address and share

    mapping(address => uint) shares;


    // Withdraw a share

    function withdraw() public {

        if (msg.sender.call.value(shares[msg.sender])())

            shares[msg.sender] = 0;

    }

}

如果用户在链外调用withdraw(),那么UnsafeContract1将以良性方式运行。

在这种情况下,合约发送一条消息将份额通过msg.sender.call.value()转给用户,然后通过更新下一行中的shares将份额设置为0。

 

攻击发生的情况是,收款人是一个合约而非用户。当合约调用方调用withdraw()时,被调用者执行msg.sender.call.value()并将执行控制权传递给调用者即合约,在这种情况下可以回调到withdraw()。

区块链 智能合约安全 重入攻击(re-entrancy attack)DAO incident_区块链

 

请注意,在withdraw()中,只有在if(msg.sender.call.value())终止后,调用方的shares才会更新为0。当恶意合约回调withdraw()时,它实际上是通过强制它停留在if()指令,来防止程序指针更新shares。这允许恶意合约多次提款,直到其燃料费被消耗殆尽。

如果收款人是用户而非合约,那么他将无法回调合约,因此执行将按预期结束。

这种攻击也被称为重入攻击(re-entrancy attack)。

 



作者:Zilliqa爱好者中文社区
链接:https://www.jianshu.com/p/5379e44280f5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。