最新消息:本站技术交流 QQ 群:28124927

自毁合约漏洞利用与防范

区块链/比特币 exchen 146浏览 0评论

自毁合约漏洞利用与防范

selfdestruct 可以自毁合约,这个函数有两个功能,一个是自毁合约,还有一个是强制发送主币ETH到任一地址。如果向一个合约发送主币ETH,这个合约没有接受主币ETH的回退函数,是不能发送成功的,而使用 selfdestruct 可以强制发送。

测试自毁合约

下面我们编写两个合约,测试自毁合约的功能,第一个合约名称为 SelfKill,构造函数添加 payable 属性,用于在创建合约时添加币。kill 函数调用了 selfdestruct 自毁合约。testFun 函数随便返回一个值,用于验证合约销毁的效果,如果返回 0 说明合约已经被销毁,数据被清空。withdraw 函数用于测试发送主币ETH,如果接受地址是一个合约,必须要有回退函数,否则发送会失败,但如果使用自毁的特点就可以强制发送,这个是主要的测试点,getBalance 函数很简单,就是返回当前合约的主币ETH数量。具体代码如下:

第二个合约用于调用 SelfKill 合约,调用自毁函数和验证接受币是否成功,名称为 Test,去掉 receive 回退函数,代码如下:

首先布署 SelfKill 合约,给一个ETH,布署成功后,点击 getBalance 可以看余额有 1 个 ETH,点击 testFun 返回 111。

然后布署 Test 合约,接着执行 SelfKill 合约的 withdraw 填入 Test 合约地址,尝试发送 1 wei 主币,可以看出提示错误,这是因为 Test 函数没有回退函数,如下图所示:

自毁合约可以向任一地址强制发送主币,不管合约代码里有没有回退函数,在 Test 合约的 TestKill 函数里填入 SelfKill 合约的地址,执行操作后,会调用 SelfKill 合约里的 Kill 函数,实现自毁。这时可以发现 SelfKill 自毁后,该合约的所有主币都转入了 Test 函数,并且 SelfKill 函数的数据也是空的,如下图所示:

漏洞利用

通过上面的自毁合约的测试,我们已经了解到 selfdestruct 的作用,接下来测试漏洞的利用,示例代码:https://solidity-by-example.org/hacks/self-destruct。示例代码里有两个合约,第一个合约名称是 EtherGame,它是一个游戏,每个用户每次只可以投 1 个 ETH,谁投到第 7 个谁就是赢家,赢家可以将所有币都取走,代码如下:

第二个函数是攻击合约,名称是 Attack,代码里添加回退函数 receive 用于添加 ETH 测试方便,在 attack 函数里调用了 selfdestruct 将自身合约销毁,并所有主币ETH强制发送给 EtherGame 合约,如果发送的数量大于7,必然会导致 EtherGame 合约判断赢家出现逻辑错误,提示 Game is over。

防范

上面的漏洞主要原因是使用 address(this).balance 做数量的判断,但这个数量并不一定是 deposit 函数打入的,有可能是其他方式,比如自毁合约这种方式打入,这样就造成的业务逻辑出现错误。为了防止其他方式的干扰,合约开发者应该只对 deposit 里的数量做记录,修t复后的代码如下:

在做合约计审时,要多注意观察 address(this).balance 的数量会不会影响业务逻辑,如果有影响的话,很有可能合约存在被攻击者强制打入币,造成正常业务逻辑错误。

转载请注明:exchen's blog » 自毁合约漏洞利用与防范

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址