SharkTeam:十大智能合约安全威胁之重入攻击
2022-9-5 13:58:26 Author: www.aqniu.com(查看原文) 阅读量:10 收藏

SharkTeam:十大智能合约安全威胁之重入攻击

问:我们常提到的智能合约漏洞真的是实际中威胁最大、发生最频繁的安全漏洞吗?

答:完全不是那样。例如“溢出”、“外部调用”等常提到的智能合约安全漏洞并不是最常发生,威胁最大的。

到底哪些安全威胁从发生频率和危害性上能称为Top10的呢?SharkTeam合约安全系列课程之【十大智能合约安全威胁】和您一起讨论和深入。第一课【详解重入攻击】。

计算机程序或子程序在执行过程中中断,然后在它前一次调用完成执行之前再次进行调用,那么该程序或子程序称为重入程序。中断可能是由内部操作(如jump或call)或外部操作(如interrupt 或signal)引起的。重入调用完成后,以前的调用将恢复正常执行。使用某些代码段执行此操作将导致重入攻击。

在以太坊智能合约中,合约能够调用和利用其他外部合约的代码。合约在正常执行期间可以通过执行函数调用或者简单地转移以太币来执行对其他合约的调用。这些外部调用可以被攻击者劫持,从而强制合约执行下一步代码(即通过fallback函数),包括回调自身。在这种情况下,我们可以说合约被重入。

重入攻击的类型可以分为:

(1)单函数重入

(2)跨函数重入

(3)跨合约重入

1.1单函数重入

当一个易受攻击的函数是攻击者试图递归调用的同一个函数时,就会发生单函数重入攻击。

在此示例中,注释(1)部分进行资金转移之后,才对注释(2)账户余额状态进行修改。这时候,会让黑客可以在状态修改之前利用fallback()函数多次调用该函数,直至取走合约账户内的全部余额。

1.2跨函数重入

当一个易受攻击的函数与一个可被攻击者利用的函数共享状态时,就会发生跨函数重入。

在此示例中,黑客可以利用fallback()操作该合约,外部调用transfer()函数,在合约余额状态设置为0之前,进行转移资金。虽然该合约能接受到取款,但是也可以转移资金。

跨函数重入和单函数重入在同一个合约中,也有不在同一个合约,重入可以发生在跨多个合约,便是多个合约共享同一个状态。

1.3跨合约重入

当一个合约中的一个状态在另一个合约中使用,但在被调用之前未完全更新时,可能会发生跨合约重入。

跨合约重入所需以下条件:

(1)一个合约中的状态在另一个合约中共享或者使用

(2)攻击者可以通过利用执行流来操纵合约的状态

重入攻击是智能合约最常见的攻击之一,这在之前许多攻击事件中都可以看到。

2021年8月17日,BSC上DeFi项目XSURGE遭遇闪电贷攻击。当地时间8月16日,XSURGE官方在遭攻击前曾发布了关于SurgeBNB漏洞的声明,由于SurgeBNB合约不可更改且已被放弃,因此无法修补该漏洞。XSURGE称没有透露任何关于此漏洞性质的具体细节,但强烈建议用户尽快迁移出SurgereBnb,该漏洞随时可能被攻击者触发。在声明发布后,XSURGE随后便遭遇攻击,攻击者在SurgeBNB中窃取了500万美元。

这次攻击交易hash:0x7e2a6ec08464e8e0118368cb933dc64ed9ce36445ecf9c49cacb970ea78531d2

攻击过程如下:

(1)首先攻击合约通过闪电贷从PancakeSwap中借了10000 BNB

(2)攻击合约使用10000 BNB买入SURGE,将买入的BURGE卖出,调用BurgeToken合约中的sell函数。在BNB转账的时候,攻击合约再次将收到的BNB转账到了BurgeToken合约中,再次触发了购买BURGE的业务。根据sell函数的代码以及BurgeToken合约的receive函数,的确可能在sell过程中发生转账,然后在sell函数尚未修改状态变量之前再次购买BURGE。

(3)在sell函数中重入了purchase函数,在重入的purchase函数中,_totalSupply没有减掉sell函数中卖出的BNB数量,造成可以买入更多的SURGE。

(4)攻击者合约中获取了高达3,896,288,852,239,440,000 BURGE,兑换成BNB有22191 BNB,偿还了闪电贷以及手续费10030 BNB,剩余的12161 BNB为攻击者此次攻击获取的利润,最后将获得的BNB转入到攻击者的账户。

2022 年 3 月 16 日,Gnosis 链上的借贷类协议 Hundred Finance 与 Agave 均遭遇了闪电贷袭击,包括 AAVE 的分支 Agave 和 Compound 的分支 Hundred Finance 。损失超1100万美元。

这次攻击交易hash:0x534b84f657883ddc1b66a314e8b392feb35024afdec61dfe8e7c510cfac1a098

攻击过程如下:

(1)从SushiSwap上通过闪电兑借出USDC和wXDAI

(2)抵押 1,200,000 个 USDC,并借贷 59,999,789.075 个 hUSDC

(3)继续超额借贷出其他代币,并且重复相同攻击多次

(4)归还闪电贷,完成攻击

可以看出,本次攻击的根本原因是因为合约存在超额借贷漏洞,通过分析具体的合约我们发现合约中存在重入问题,导致攻击者可以完成攻击并进行超额借贷。

2022 年 3 月 27 日,Revest Finance遭到黑客攻击。黑客利用了 Revest 合约的逻辑漏洞盗取了近 770 万枚 ECO、579 枚 LYXe、近 7.15 亿枚 BLOCKS 以及超 35 万枚 RENA,价值约200万美元。黑客攻击使用从 Tornado Cash 取出的资金发动了攻击,通过SushiSwap以及Uniswap将盗取的Token兑换成了ETH,最后通过Tornado Cash平台将ETH转移到了其他账户。

这次攻击交易hash:0xe0b0c2672b760bef4e2851e91c69c8c0ad135c6987bbf1f43f5846d89e691428

攻击过程如下:

(1)首先,攻击者通过UniswapV2的闪电兑换功能调用Revest合约中的mintAddressLock函数

(2)攻击者第一次调用mintAddressLock函数铸造了2个ID为1027的Token。第二次调用mintAddressLock函数铸造了360000个ID为1028的Token。

(3)在mintAddressLock函数完成前调用_mint函数时,攻击者重入了depositAdditionalToFNFT函数【ERC1155 onERC1155Received 重入】。

(4)由于NFT nextId(即FNFTHandler.fnftsCreated)在mint函数铸造NFT完成并进行更新。因此,在重入调用depositAdditionalToFNFT函数时,NFT Id仍然是1027,nextId任仍然是1028。另外,合约并未验证1028的Token数量是否为0,攻击者再次成功地铸造了1个ID为1028的NFT。

2022年7月10日,去中心化金融协议NFT市场Omni因智能合约漏洞遭到黑客闪电贷攻击,耗尽了1300ETH,约143万美元。

这次攻击交易hash:0x264e16f4862d182a6a0b74977df28a85747b6f237b5e229c9a5bbacdf499ccb4

攻击过程如下:

(1)首先,攻击者通过Balancer借贷平台闪电贷1000 ETH

(2)通过函数flashLoan闪电贷20个DOODLE

(3)通过SushiSwap平台使用WETH兑换了1个DOODLE

(4)赎回20个NFT,tokenId = 2574, 2595, 6851, 8522, 8883, ……

(5)抵押NFT(supplyERC721),tokenId = 5251, 4777, 3693,然后铸造nDOODLE

(6)借贷WETH(borrow),数量为12.15 ETH

(7)提取抵押的3个NFT中的2个,tokenId = 5251, 4777

(8)销毁抵押NFT时铸造的nDOODLE,然后调用safeTransferFrom函数将抵押的NFT转移到攻击合约,攻击者利用onERC721Received函数发起了重入攻击

(9)质押的3个NFT提取了两个,还剩下一个tokenID = 3693的NFT,此时抵押仓位,攻击者在重入攻击中实现了自我清算,清算完成后,将借贷设置为false。

(10)在转移剩下的NFT时再次发生重入,此次重入,攻击者抵押了全部的20个NFT,然后铸造nDOODLE,以此做抵押,借贷了81 WETH。最后,将所有的20个NFT提取出来。

(11)重复以上抵押、铸造、销毁等操作,最终获利148.8 ETH。

在本次事件中,由于safeTransferFrom函数调用onERC721Received函数引起的重入漏洞。攻击者利用该漏洞发起了重入攻击,最终获利。

回顾了这么多的重入攻击事件,可想而知重入漏洞在智能合约中是多么常见。

”2022中国国际金融年度论坛“于2022年9月2日在北京举行,中国人民银行数字货币研究所所长穆长春发表了关于”智能合约与数字人民币“主题演讲。穆长春表示,数字人民币智能合约应用场景比较广泛,可以降低经济活动的履约成本,优化营商环境,推动数字经济深化发展。由于智能合约的可信任、可互通优势,可以更好的支撑数字经济。

一边是推动智能合约与数字人名币的发展,一边是频繁发生的合约安全问题,我们应该采取哪些有效预防措施,避免损失,保障安全?

(1)对于单函数重入、跨函数重入,可以在合约中实现互斥锁,用来防止重复调用同一个合约中的函数,从而防止重入。实现锁的一种广泛使用的方法是继承OpenZeppelin的ReentrancyGuard并使用nonReentrant修饰符。

(2)在调用外部合约或所谓的“检查-生效-交互”模式之前检查并尝试更新所有状态。这样,即使重入,也不会产生任何影响,因为所有状态都已完成更新

(3)防止攻击者利用合约的控制流。设置一组列入白名单的地址,可以防止攻击者将未知的恶意合约注入合约

(4)采用pull-payment,它通过中间托管发送资金并且避免直接接触潜在敌对合同来实现安全性,比如OpenZeppelin的PullPayment,他是pull-payment策略的简单实现

(5)gas限制可以防止重入攻击,但这不应该被视为一种安全策略,因为gas成本取决于以太坊的操作码,这些操作码可能会发生变化。另一方面,智能合约代码是不可变的。无论如何,有必要了解这些函数之间的区别:send,transfer和call。send和transfer的函数本质上是相同的,但如果事务失败,transfer将恢复,而send则不会。关于重入,send和transfer都有2300个单位的gas限制。使用这些函数应该可以防止发生重入攻击,因为这不足以递归回调源函数来利用资金

(6)使用自动化的智能合约审计扫描工具或需求专业的第三方审计团队的帮助,也可以帮助检测重入错误。


文章来源: https://www.aqniu.com/vendor/88702.html
如有侵权请联系:admin#unsafe.sh