selfdestruct函数(自毁函数)由以太坊智能合约提供,用于销毁区块链上的合约零碎。当合约执行自毁操作时,合约账户上残余的以太币会发送给指定的指标,而后其存储和代码从状态中被移除。
selfdestruct函数尽管能在紧急情况下帮忙开发人员删除智能合约并将合约内的余额转移到指定的地址,但这一个性也被不法分子利用,使它成为了攻打伎俩。让咱们来看个经典游戏“侥幸7”的案例:

合约代码

破绽剖析

在“侥幸7”游戏中,玩家每次向 EtherGame 合约中打入一个ETH,第七个胜利打入ETH的玩家将成为 winner。winner 能够提取合约中的 7 个ETH。玩家每次玩游戏时都会调用 EtherGame.deposit 函数向合约中先打入一个ETH,随后函数会查看合约中的余额(balance)是否小于等于 7 ,只有合约中的余额小于等于 7 时能力持续否则将回滚。合约中的余额(balance)是通过 address(this).balance 取到的,这就意味着咱们只有有方法在产生 winner 之前扭转 EtherGame 合约中的余额让他等于 7 就会使该合约瘫痪。这样咱们的攻打方向就明确了,只有咱们强制给 EtherGame 合约打入一笔ETH让该合约中的余额大于7 这样前面的玩家将无奈通过 EtherGame.deposit 的查看,从而使 EtherGame 合约瘫痪,永远无奈产生 winner。然而 EtherGame.deposit 函数中存在验证:require(msg.value == 1 ether, "You can only send 1 Ether"),这里要求咱们每次只能打一个ETH进去,所以通过失常门路是不可能一次向 EtherGame 打入大于 1 枚的ETH的,然而咱们又须要打入大于 1 枚的ETH到 EtherGame 合约中,所以selfdestruct函数就退场了。

攻打合约


 攻击者调用攻打函数attack()销毁合约并将合约中的余额强制转账到“侥幸7”的游戏合约地址,制作出游戏合约查问余额address(this).balance大于7的状况,导致函数回退,无奈失常进行游戏的状况,使得游戏合约瘫痪。修复倡议咱们来剖析一下攻击者的思路:利用selfdestruct函数强制转账给游戏地址,导致unit balance = address(this).balance查问出的balance的值大于7,诱发require(balance <= targetAmount, "Game is over");无奈通过使得游戏合约瘫痪。咱们不难发现攻击者是通过影响balance从而达到目标的,那么咱们就让balance不受这个影响,在最后先定义balance,再让balance的值只受通过游戏规则内的失常路径的影响,这样就不会呈现balance值异样的状况了。

修复的代码:


如果想理解更多的智能合约和区块链常识,欢送到区块链交换社区CHAINPIP社区,一起交流学习~ 
社区地址:https://www.chainpip.com/