THE:深入理解重入攻击漏洞

摘要:重入攻击本质上与编程里的递归调用类似,当合约将以太币发送到未知地址时就可能会发生,威胁以太坊智能合约的安全性。知道创宇区块链安全实验室?从转账方法、fallback函数、漏洞代码、源码分析四个方面入手,深入分析攻击原因,详解?The?DAO事件。

前言

智能合约的概念于1995年由NickSzabo首次提出,它是一种旨在以信息化方式传播、验证或执行合同的计算机协议,它允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。

然而智能合约也并非是安全的,其中?重入(Re-Entrance)攻击?漏洞是以太坊中的攻击方式之一,早在2016年就因为TheDAO事件而造成了以太坊的硬分叉。

漏洞概述

在以太坊中,智能合约能够调用其他外部合约的代码,由于智能合约可以调用外部合约或者发送以太币,这些操作需要合约提交外部的调用,所以这些合约外部的调用就可以被攻击者利用造成攻击劫持,使得被攻击合约在任意位置重新执行,绕过原代码中的限制条件,从而发生重入攻击。重入攻击本质上与编程里的递归调用类似,所以当合约将以太币发送到未知地址时就可能会发生。

简单的来说,发生重入攻击漏洞的条件有2个:

调用了外部的合约且该合约是不安全的

外部合约的函数调用早于状态变量的修改

下面给出一个简单的代码片段示例:

7位Doodles NFT巨鲸在Blur pool中共抛售逾400枚Doodles:5月21日消息,据 Blur Dumping Bot 统计,今日 12:00 开始,7 位 Doodles NFT 巨鲸在 Blur pool 中抛售的 Doodles NFT 数量超过 400 枚,其中,0xf50991 开头地址在三笔交易中共抛售 142 枚 NFT(三笔平均售价分别为:2.5 ETH、2.46 ETH、2.39 ETH),0x43bfF0 开头地址通过 2 笔交易抛售 102 枚 NFT,0x09e949 开头地址抛售 30 枚 NFT,0xcEc5D5 开头地址抛售 50 枚 ETH,0x4BD88f 开头地址抛售 44 枚,0x05c85f 开头地址抛售 20 枚,0x5e1416 地址抛售 31 枚 NFT(平均售价 2.09 ETH)。[2023/5/21 15:16:46]

上述代码片段就是最简单的提款操作,接下来会给大家详细分析重入攻击造成的原因。

漏洞分析

在正式的分析重入攻击之前,我们先来介绍几个重点知识。

转账方法

由于重入攻击会发送在转账操作时,而Solidity中常用的转账方法为

<address>.transfer(),<address>.send()和<address>.gas().call.vale()(),下面对这3种转账方法进行说明:

<address>.transfer():只会发送2300gas进行调用,当发送失败时会通过throw来进行回滚操作,从而防止了重入攻击。

LTC在周三达到一个月高点:金色财经报道,据CoinDesk的数据,莱特币(LTC)在更广泛的市场平静中度过了一段时光,在过去7天里上涨了15%,周三达到一个月高点95美元。截至发稿时,它已回落至92美元。行情波动较大,请做好风险控制。

据Coinglass数据,锁定在与莱特币相关的未平仓期货合约数量中的美元价值已升至4.78亿美元,为12月初以来的最高水平。

根据Matrixport研究和战略主管Markus Thielen的说法,BRC-20的一个分支出现在Litecoin上,称为LTC-20,使Litecoin的网络比以往更加繁忙。5月10日,确认交易数和活跃地址数分别达到58万和83万的历史新高。

据Matrixport,莱特币的第三次奖励减半将在不到80天的时间内到期。[2023/5/18 15:11:52]

<address>.send():只会发送2300gas进行调用,当发送失败时会返回布尔值false,从而防止了重入攻击。

<address>.gas().call.vale()():在调用时会发送所有的gas,当发送失败时会返回布尔值false,不能有效的防止重入攻击。

fallback函数

接着我们来讲解下fallback回退函数。

回退函数(fallbackfunction):回退函数是每个合约中有且仅有一个没有名字的函数,并且该函数无参数,无返回值,如下所示:

function()publicpayable{???

???...

比特小鹿一季度总收入为7260万美元:5月16日消息,吴忌寒旗下矿业公司比特小鹿Bitdeer公布2023年第一季度未经审计的财务业绩和运营更新。根据该报告,比特小鹿第一季度总收入为7260万美元,较2022年同期(9040万美元)减少19.7%;净亏损为950万美元,而2022年同期为净亏损960万美元。2023年第一季度调整后利润为280万美元,而2022年同期为2560万美元。

截止3月31日,比特小鹿总管理算力为18.3 EH/s,其中专有算力为5.7EH/s(自挖业务为3.9 EH/s,云算力业务为1.8 EH/s);托管算力为12.6 EH/s。自挖业务在2023年第一季度开采了552枚比特币,而2022年同期为538枚比特币。总部署矿机约196,000台ASIC矿机,其中67,000台用于自挖业务和云算力业务,129,000台用于托管。2023年第一季度,公司五个采矿数据中心的总用电量约为992,700 MWH。(Globenewswire)[2023/5/16 15:04:56]

}

回退函数在以下几种情况中被执行:

调用合约时没有匹配到任何一个函数;

没有传数据;

智能合约收到以太币。

漏洞代码

下面的代码就是存在重入攻击的,实现的是一个类似于公共钱包的合约,所有的用户都可以使用deposit()存款到Reentrance合约中,也可以从Reentrance合约中使用withdraw()进行提款,当然了所有人也可以使用balanceof()查询自己或者其他人在该合约中的余额。

EOS EVM将于3月27日推出最终测试网:3月23日消息,EOS网络基金会在社交媒体发文称,EOS EVM(TrustEVM)的代码已准备就绪,将如期于3月27日推出最终测试网,主网测试将于4月14日上线。[2023/3/23 13:21:15]

首先使用一个账户(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4)扮演受害者,将该合约在RemixIDE?点击Deploy按钮进行部署。

在部署合约成功后在VALUE设置框中填写5,将单位改成ether,点击deposit存入5个以太币。

点击wallet查看该合约的余额,发现余额为5ether,说明我们的存款成功。

而下面的代码则是针对上面存在漏洞的合约进行的攻击:

马耳他区块链暨比特币大会:深入探讨国家区块链战略及数字货币立法问题:上周,在马耳他圣朱利安举办了马耳他区块链暨比特币大会(Blockchain & Bitcoin Conference Malta),对涉及加密数字货币、区块链和ICO等问题进行了深入探讨。马耳他政府的高级官员和国家区块链战略制定者们出席了本次会议。据悉,本次大约吸引400位业内人士参会,包括行业开发人员、投资人、企业家、银行和信贷机构代表、以及金融科技专家、律师和记者等。观众听取了20位嘉宾的演讲,同时也有15家公司登台进行了展示。[2017/12/13]

使用另外一个账户(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2)扮演攻击者,复制存在漏洞的合约地址到Deploy的设置框内,点击Deploy部署上面的攻击合约。

部署成功后先调用wallet()函数查看攻击合约的余额为0。

攻击者先存款1ether到漏洞合约中,这里设置VALUE为1ether,之后点击攻击合约的deposit进行存款。

再次调用合约的wallet函数查看漏洞合约的余额,发现已经变成了6ether。

攻击者(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2)调用攻击合约的attack函数模拟攻击,之后调用被攻击合约的wallet函数去查看合约的余额,发现已经归零,此时回到攻击合约查看余额,发现被攻击合约中的6ether已经全部提款到了攻击者合约中,这就造成了重入攻击。

源码分析

上面讲解了如何进行重入攻击已经漏洞原因,这里梳理了漏洞源码和攻击的步骤,列出了关键代码。

相关案例

2016年6月17日,TheDAO项目遭到了重入攻击,导致了300多万个以太币被从TheDAO资产池中分离出来,而攻击者利用TheDAO智能合约中的splitDAO()函数重复利用自己的DAO资产进行重入攻击,不断的从TheDAO项目的资产池中将DAO资产分离出来并转移到自己的账户中。

下列代码为splitDAO()函数中的部分代码,源代码在TokenCreation.sol中,它会将代币从theparentDAO转移到thechildDAO中。平衡数组uintfundsToBeMoved=(balances*p.splitData.splitBalance)?/p.splitData.totalSupply决定了要转移的代币数量。

下面的代码则是进行提款奖励操作,每次攻击者调用这项功能时p.splitData都是一样的,并且p.splitData.totalSupply与balances的值由于函数顺序问题,发生在了转账操作之后,并没有被更新。

paidOut+=reward更新状态变量放在了问题代码payOut函数调用之后。

对_recipient发出.call.value调用,转账_amount个Wei,.call.value调用默认会使用当前剩余的所有gas。

解决办法

通过上面对重入攻击的分析,我们可以发现重入攻击漏洞的重点在于使用了fallback等函数回调自己造成递归调用进行循环转账操作,所以针对重入攻击漏洞的解决办法有以下几种。

使用其他转账函数

在进行以太币转账发送给外部地址时使用Solidity内置的transfer()函数,因为transfer()转账时只会发送2300gas进行调用,这将不足以调用另一份合约,使用transfer()重写原合约的withdraw()如下:

先修改状态变量

这种方式就是确保状态变量的修改要早于转账操作,即Solidity官方推荐的检查-生效-交互模式(checks-effects-interactions)。

使用互斥锁

互斥锁就是添加一个在代码执行过程中锁定合约的状态变量以防止重入攻击。

使用?OpenZeppelin官方库

OpenZeppelin官方库中有一个专门针对重入攻击的安全合约:

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol

参考文献

1.以太坊的几次硬分叉:

https://zhuanlan.zhihu.com/p/111446792

2.以太坊智能合约安全漏洞(1):重入攻击:

https://blog.csdn.net/henrynote/article/details/82119116

3.?区块链的那些事—THEDAO攻击事件源码分析:

https://blog.csdn.net/Fly_hps/article/details/83095036

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

链链资讯

FilecoinBTC:站在十字路口的中国比特币矿工

时间是2021年5月25日,王力穿着厚厚的医务防护服,在国际航班候机楼内,全副武装等待起飞。毕竟海外疫情尚未稳定,诺大的国际候机楼此时显得空荡荡,没人会在这个时间出国,除非必要情况,比如王力的情.

[0:15ms0-3:236ms