当前位置: 首页 > Web前端 > vue.js

智能合约安全-溢出漏洞

时间:2023-03-31 19:20:45 vue.js

算术溢出(arithmeticoverflow)或简称溢出(overflow)分为溢出和下溢两种。所谓溢出,是指在运行单个数值计算时,当计算结果非常大,大于寄存器或内存所能存储或表示的容量极限时,就会溢出;而下溢是在计算结果非常大的时候。小,小于寄存器或内存存储或表示的容量极限,就会发生下溢。例如:在solidity中,uint8可以表示的范围是0到255之间的256个数字。如果某个合约存在溢出漏洞,会造成实际计算结果与预期结果相差非常大,从而影响轻则合约正常逻辑,重则导致合约资金流失。但是,溢出漏洞存在版本限制。当Solidity<0.8时,溢出不会报错,当Solidity>=0.8时,溢出会报错。所以当我们看到0.8版本以下的合约时,一定要注意这个合约可能存在的溢出问题。漏洞示例通过以上的讲解,相信大家对溢出漏洞有了一定的了解。下面结合合约代码深入了解溢出漏洞:漏洞分析TimeLock合约作为一个时间保险库,用户可以通过存款功能存入代币。进入合约并锁定,至少一星期内不能提现。当然用户也可以通过increaseLockTime函数增加存储时间。在设置的存储期限到期之前,用户无法提取锁定在TimeLock合约中的代币。首先,我们发现这个合约中的increaseLockTime函数和deposit函数是有算术函数的,而这个合约支持的版本是:0.7.6向上兼容,所以这个合约在算术溢出的时候不会报错,那么我们可以判断这个合约可能存在溢出漏洞。这里有两个函数可以使用,一个是increaseLockTime函数,一个是存款函数。在决定如何发起攻击之前,我们先分析一下这两个函数可以影响的参数范围:deposit函数中有两个操作,第一个是影响用户存入的余额,传入的参数这里是可控的所以这里会存在溢出的风险,另外一个就是影响用户的锁仓时间lockTime,但是这里的操作逻辑是每次调用充币充值都会在lockTime上加一周。由于这里的参数是不可控的,所以这个操作是无效的。有溢出的危险。increaseLockTime函数根据用户传入的_secondsToIncrease参数运行,改变用户存入代币的锁定时间。由于这里的_secondsToIncrease参数是可控的,所以有溢出的风险。综上所述,我们发现有两个可用参数,分别是存款函数中的balances参数和increaseLockTime函数中的_secondsToIncrease参数。让我们先看看balances参数。如果我们想让这个参数溢出,我们需要有足够的资金来存入它(需要存入2^256个代币才能导致余额溢出归零)。如果我们想利用这个溢出漏洞,我们将大量资金存入自己的账户,让自己账户的余额溢出归零,清空自己的资产。我认为在座的任何人都不会这样做。所以从攻击者的角度来看,这个参数可以认为是不可用的。让我们再看看_secondsToIncrease参数。这个参数是我们在调用increaseLockTime函数增加存储时间的时候传入的。这个参数可以决定我们什么时候可以从合约中取出我们存入和锁定的代币。我们可以看到这个参数传入后,是直接和账户对应的lockTime计算的。如果我们操作_secondsToIncrease参数,使得用lockTime操作后得到的结果溢出并归零,我们是否可以将日期存储到Didyoutakethebalanceinyouraccountbeforetheduedate?攻击合约我们来看一下攻击合约:这里我们将使用Attack攻击合约先存入以太币,然后利用合约的溢出漏洞在存储到期前提取我们刚刚存入并锁定在TimeLock合约中的以太币:首先部署TimeLock合约;然后部署Attack合约,在构造函数中传入TimeLock合约的地址;调用Attack.attack函数,Attack.attack调用TimeLock.deposit函数向TimeLock合约存入一个以太币(此时以太币会被TimeLock锁定一周),然后Attack.attack调用TimeLock.increaseLockTime函数并传入uint类型的最大可表示值(2^256-1)加1再减去当前TimeLock合约记录的锁定时间。此时TimeLock.increaseLockTime函数中lockTime的计算结果为2^256。在uint256类型中,数字2^256溢出,所以计算结果为2^256=0。此时,我们刚才在TimeLock合约中存储的值1个以太的锁定时间变为0;此时Attack.attack调用TimeLock。withdraw函数会成功通过block.timestamp>lockTime[msg.sender]这个检查可以让我们在存储时间还没有过期的情况下成功提前提取我们刚刚存入并锁定在TimeLock合约中的以太币。以下是攻击流程图:修复建议接下来我们说说如何修复这些漏洞?显然,防止数据值溢出可以修复这些漏洞,所以我给大家一些防止数据值溢出的建议!1、使用Solidity0.8及以上版本开发合约,这里还有一点:需要谨慎使用unchecked,因为unchecked代码块中的参数不会进行溢出检查;2、使用SafeMath方法库,SafeMath只提供简单的算术方法,但是当计算溢出时,会抛出错误;另外,作为合约编写者,需要谨慎使用变量类型转换,因为不同的类型有不同的取值范围,类型强制转换可能会导致数值溢出。如果你想了解更多智能合约和区块链知识,欢迎来到区块链交流社区CHAINPIP社区一起交流学习~社区地址:https://www.chainpip.com/