Cointime

扫码下载App
iOS & Android

导致 DAO黑客事件频发的“重入攻击”是什么?

个人专家

作者:Immunefi 编译:CoinTime 237

重入攻击在以太坊中已经有很长的历史,并且是导致 DAO黑客事件的漏洞类别之一,该事件是2016年早期以太坊网络遭受的最大攻击之一。自那时以来,许多标准已被引入以减轻这类漏洞,例如限制由外部保护程序转发的gas、重入保护程序以及遵循Checks-Effects-Interactions(CEI)模式。

许多人现在甚至质疑重入的相关性作为一个重要的漏洞,因为攻击向量及其模式已广为人知。然而,看看最近的黑客攻击和事件,情况却截然不同。

自Paweł Kuryłowicz撰写关于Solidity中重入攻击是否仍然存在问题的文章以来已经有一些时间了。在2021年,Pawel提出了以下问题:

好吧,但是这种重入攻击是一个重大问题吗?

答案是:

是的,它是一个重大问题。

到目前为止,重入攻击仍然是一个重大问题,而且在可预见的未来可能仍将如此。

重入如何影响生态系统?

自Pawel发布他的文章以来,已经有数亿美元因重入攻击而遭受损失,其中最著名的是Fei的Rari Fuse Pools事件,据报道损失超过8000万美元。尽管重入是最常被引用的智能合约漏洞之一,也是许多安全研究人员首次接触智能合约安全的方式,但仍有许多项目会因为这种漏洞而受到攻击。您可以在pcaversaccio的存储库"A Historical Collection of Reentrancy Attacks"中查看受影响的项目。

什么是重入?

重入是一个状态同步问题。当向另一个智能合约进行外部调用时,执行流控制被传递。调用合约必须确保所有全局共享状态在传递控制之前完全同步。由于EVM是单线程机器,如果一个函数在传递执行控制之前没有完全同步状态,则该函数可以使用与第一次调用时相同的状态重入。这可能会导致该函数重复执行本来只打算执行一次的操作。

如果我们对 WETH 合约进行一个简单的修改,将原生资产以太包装成 ERC20 兼容的代币,我们就可以更好地理解可能导致重入的反模式。存款功能接收以太币并增加存储在映射中的用户余额balanceOf。

当用户想将他们的 WETH 转换回以太币时,他们调用withdraw. 当该withdraw函数使用低级调用将以太币转移给用户时,执行流程将转移到接收者。在此示例中,在更新余额之前进行外部调用。如果调用方是 EOA,则转账成功完成并在撤回函数内继续执行。但是,如果调用者是智能合约,则调用默认的 payable 函数,可以控制它做任何我们喜欢的事情。

在我们执行默认支付功能期间,WETH 合约不知道它已经发送了以太币,因为映射balanceOf尚未被修改!如果我们回调该withdraw函数,检查我们是否有足够的 WETH 余额来提取以太币的 require 语句将会通过。我们刚刚破解了 WETH 合约并获得了无限的以太币!

* 一旦所有可重入调用都解决,balanceOf映射仍然根据调用函数的次数减少。在 Solidity 版本 >= 0.8.0 中,这将导致整个功能恢复,因为默认情况下发生下溢/溢出检查。然而,任何低于此的 Solidity 版本都将导致余额不足,攻击者将额外获得非常大的余额。

你能做些什么来防止重入?

fallback重入的第一个案例发生在以太币的传输中,因为代码执行在本机资产传输期间被转移到接收函数。这些函数send和transfer被引入地址类型以传输以太币,但限制转发给接收者的gas量以限制可以执行的逻辑。这减轻了潜在的 gas griefing 风险,并防止了重入,因为内部调用会在能够执行必要的逻辑之前耗尽 gas。然而,这个解决方案也有缺点。使用transfer或send将破坏与智能合约的可组合性,智能合约可能在回退函数中出现一些必要的逻辑,例如代理,它将它们的逻辑委托给实现合约。

由于操作码的 gas 成本可能会发生变化,这可能会破坏依赖于这些调用期间传递的有限 gas 量的现有合约,因此建议不要使用和send。ConsenSys 在他们的文章Stop Using Solidity's transfer() Nowtransfer中详细介绍了这个问题,但是因为 gas 成本可能会发生变化并且有更有效的方法来减轻重入风险,如果遵循最佳实践则不应使用。sendtransfer

防止重入的最推荐和最简单的方法是实施检查-效果-交互 ( CEI ) 模式。那些执行外部调用的函数应该确保所有外部交互发生在任何检查或状态更改之后。这也就是传统并发编程中俗称的尾调用模式。如果我们要在withdrawWETH 函数中修复前面的示例,我们将首先有检查用户是否有足够的 WETH 余额的 require 语句(检查),对存储进行更改以更新用户余额(效果),最后使外部调用用户转移资金(交互)。

最后,如果协议的无权限操作可能会引入未知风险,则reentrancyGuard可以使用 a 来确保无法在同一调用框架内多次调用该函数。OpenZeppelin 提供了一个用于实现ReentrancyGuards 的库。但是,执行 SLOAD 和 SSTORE 以检查函数是否已被调用的额外 gas 成本将增加 gas 成本,如果遵循推荐的模式,则可能没有必要。此外,这种类型的重入守卫不会防止跨合约重入。

* EIP-1153旨在通过为每次交易后丢弃的数据引入新的操作码来降低此成本

什么可以触发重入?

如果没有遵循正确的 CEI 模式,任何外部调用都可能导致重入。Slither是一个开源静态分析框架,可以帮助审计人员和漏洞猎手找到潜在的可重入漏洞入口点。但是,以下标准是执行流程可以转移到任意合约的方式的几个示例:

低级别调用(.call())

transferERC223 代币

transferAndCallERC667 代币

transferERC777 代币

safe*ERC1155代币的传递函数

*AndCallERC1363代币的功能

safe*ERC721 代币safeTransfer等功能safeMint

transfer某些 ERC20 代币可能已经为接收者实现了自定义回调函数

重入有哪些不同类型?

1、单函数重入

这是最简单的重入类型,导致了 6000 万美元的 The DAO Hack 和以太坊网络的硬分叉,导致创建了单独的区块链、未改变的“以太坊经典”以及我们今天所知的改变历史的以太坊网络.

当合约在完成状态更改之前进行外部调用,并且在外部调用中重入相​​同的函数时,就会发生单函数重入。

2、跨函数重入

攻击者还可以使用共享相同状态的两个不同函数进行类似的攻击。如果第一个函数在共享数据更新之前进行外部调用,则攻击者可能会以未更改的状态进入第二个函数。

如果两个函数都有一个守卫, OpenZeppelin 的重入守卫nonReentrant可能会阻止这个问题,因为它们共享相同的存储值作为检查该函数是否已被调用的值。nonReentrant这也可以防止在同一个调用框架内调用带有修饰符的函数。

3、跨合约重入

重入不限于调用同一合约中的函数。共享相同状态的多个合约也容易受到重入的影响。同样,CEI 模式可以防止任何重入风险。但是,如果共享状态在外部调用之前没有更新,重入可能会导致严重的漏洞。您可以在Phuwanai Thummavet 的这个例子中阅读更多关于跨合约重入的信息。

4、只读重入

通常,审计员和漏洞猎手在寻找重入时只关心修改状态的入口点。但是,当协议依赖于读取另一个协议的状态时,可能会发生只读重入。最值得注意的是,通过在移除流动性的过程中重入视图函数,Curvesget_virtual_price很容易受到此类攻击。get_virtual_price在许多情况下,这会影响依赖于另一个定价机制的协议,因此项目在集成交易所价格预言机或其他流动性管理协议时应该非常小心。在Curve LP Oracle Manipulation: Chain Security 的Post Mortem中阅读更多关于野外只读重入的信息。此外,您可以在 SunWeb3Sec 的DeFiVulnLabs中找到只读重入的示例常见的智能合约漏洞存储库。

5、跨链重入

跨链重入是最新类型的重入攻击,随着跨链消息传递协议的兴起,它最近才开始受到关注。在野外没有跨链重入攻击的先例。然而,随着跨链互操作性和多链未来统一愿景的兴起,任何在链之间桥接资产或利用跨链消息传递的协议都必须理解和审查这种范式。可以在此处查看专门为演示跨链可重入性而创建的示例。

重入的未来?

在EIP-1153TSTORE中引入新的瞬态存储操作码为改进智能合约中的重入保护提供了机会。这些操作码允许将数据存储在合同功能完成后重置的临时位置,使攻击者无法重入功能。通常,可重入守卫是使用存储实现的。话虽这么说,但操作码的 gas 成本很高。OpenZeppelin 的重入守卫可能会改为使用更省油的瞬态存储操作码。TLOADSSTORESLOAD

随着这些新操作码的添加,还有在编译器级别默认禁用重入的举措。这将为防止重入攻击提供额外的保护层,并有助于确保开发人员了解与重入代码相关的风险。Vyper和Solidity编程语言都在考虑实现此功能,这将使开发人员更容易编写安全合约,并可能导致开发人员在考虑在其智能合约中进行外部调用时的范式转变。

在此之前,重入攻击仍然是智能合约领域的一个严重问题。

因此,开发人员必须在编码实践中保持警惕并采用最佳安全实践来最大程度地降低重入攻击的风险。此外,审计员和安全研究人员在识别漏洞和向开发人员提供反馈方面发挥着至关重要的作用。通过共同努力,区块链社区可以继续提高智能合约的安全性,并通过漏洞奖励和审计防止重入攻击造成进一步的危害。

评论

所有评论

推荐阅读

  • 三男女涉虚拟货币交易平台及银行帐户洗黑钱逾18亿元被捕

    香港海关捣破一个洗黑钱集团并拘捕三名怀疑涉案本地人士,涉嫌利用虚拟货币交易平台及多个本地不同银行开设的公司帐户,处理逾18亿元的不明来历资金。海关人员根据情报锁定3名本地人士并展开财富调查,发现3人于2021年6月至2022年7月期间透过开设多间本地公司及多个银行户口,处理超过1000宗可疑交易,当中包括从虚拟货币交易平台转移的资金,涉款逾18亿元。

  • BTC 减半倒计时仅剩 1 天

    据欧科云链数据,BTC 减半倒计时仅剩 1 天 17 小时,预计在 2024/04/20 迎来减半。当前区块奖励为 6.25 BTC ,减半后区块奖励为 3.125 BTC 。目前剩余区块为 253,目前全网算力为 587.96 EH/s ,全网挖矿难度为 83.95 T,平均出块时间为 9.94 min 。

  • 美阿肯色州众议院通过限制加密货币挖矿活动的法案

    美国阿肯色州议会通过了两项法案,可能会限制该州的加密货币挖矿活动。在4月17日的参议院听证会上,议员们试图解决诸如减少噪音、外国所有权以及加密货币矿场靠近居民区等普遍问题。周三提交给众议院的八项法案中有两项通过,但参议院上周只批准了一项涉及加密货币的法案。关于第851号法案是否应该修改以及这些修改应该包含的详细程度,存在相当大的争论。相关委员会将讨论这个问题,然后可能在本届财政会议或下一届财政会议上通过一项法律。

  • 瑞典要求加密矿工缴纳 9000 万美元的未缴税款

    瑞典税务局 Skatteverket 对 2020 年至 2023 年间 21 家加密货币挖矿公司的运营情况进行了调查。调查显示,18 家加密货币挖矿公司提交了“误导性或不完整”的信息,以享受税收优惠。据该机构称,一些加密货币公司提供了误导性的业务描述,以避免缴纳应税业务的增值税(VAT)。 其他人则找到了避免缴纳采矿设备进口税或采矿收入所得税的方法。 违约的加密货币挖矿公司需要向税务机关总共支付超过 9.9 亿瑞典克朗(SEK)(9000 万美元)。 其中包括未缴增值税总额 9.32 亿瑞典克朗(8540 万美元)和约 5790 万瑞典克朗(530 万美元)的附加税。虽然加密货币矿业公司对瑞典税务局提出的 9000 万美元的要求提出上诉,但行政法院维持了两家矿业公司的上诉,并驳回了其余公司的上诉。 “上述金额已根据判决进行调整。”

  • 全网BTC期权未平仓头寸为212.4亿美元,ETH期权未平仓头寸为94.2亿美元

    Coinglass 数据显示,目前全网 BTC 期权未平仓头寸的名义价值为 212.4 亿美元,ETH 期权未平仓头寸的名义价值为 94.2 亿美元。

  • CZ推出Giggle Academy的测试网络课程

    币安前首席执行官CZ公布了最近推出的教育项目Giggle Academy的测试网络课程,CZ他的X账户上分享了一个视频片段,其中涉及一个可安装的安卓软件包(Apk)中的课程。

  • 比特币减半后新增挖矿产出将从每天900枚减至450枚

    据HODL15Capital监测,比特币减半后,其新增挖矿产出将从每天900枚减至450枚,按照当前价格,购买所有这些新增产出大约需要2800万美元。

  • BTC突破62000美元,日内跌幅收窄至2.96%

    行情显示,BTC突破62000美元,现报62008.36美元,日内跌幅收窄至2.96%,行情波动较大,请做好风险控制。

  • Tether昨日发行价值4.37亿美元USDT

    Tether 4月17日发行价值4.37亿美元的USDT,赎回1.42亿美元的USDT (发行量净增2.95亿枚USDT),价值约1亿美元的USDT发行至0x5c开头地址 (疑似Bitfinex转发地址),价值约8,100万美元的USDT发行至0x77卡头地址(疑似Bitfinex 1钱包地址)。

  • 某地址被清算43.88枚WBTC,价值274万美元

    据PeckShield监测,当BTC跌破6万美元时,地址0x2882...eb88被清算约43.88枚WBTC(价值274万美元)。