风险提示:请理性看待区块链,树立正确的货币观念和投资理念,不要盲目跟风投资,本站内容不构成投资建议,请谨慎对待。 免责声明:本站所发布文章仅代表个人观点,与CoinVoice官方立场无关

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

加密谷Live
2020年04月20日

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

作者 | PeckShield
摘 要: Uniswap/Lendf.Me 攻击事件发生的根本原因在于,ERC777 标准中原生地支持 hook (钩子)机制的运行,而在 imBTC 实现过程中,并未在相应函数间加入互斥锁,从而出现了重入攻击漏洞。黑客正是利用该漏洞对 Uniswap 与 Lendf.Me 发起攻击,以几乎接近于 0 的成本获得了巨额的数字资产。
UTC 时间 2020 年 4 月 18 日上午 12:58:19 发生了一起针对 Uniswap imBTC 流动池的重入漏洞攻击。大约 24 小时后,UTC 时间 2020 年 4 月 19 日上午 12:58:43 Lendf.Me 上也发生了类似的黑客攻击事件。从技术上讲,这两起事件背后的主要逻辑是,兼容 ERC777 的“transferFrom()”的实现有一个回调机制,这可使得攻击者可以在余额真正更新之前 (即在_move() 内部),彻底地劫持交易并执行其他非法操作 (通过“_callTokensToSend()”)。
具体来说,攻击者利用该漏洞耗尽了 Uniswap 流动性池中的 ETH-imBTC (约有 1278 个 ETH),而 Lendf.Me 攻击事件中,黑客利用该漏洞伪造了其在 Lendf.Me 中 imBTC 抵押品金额内部记录,这样他就可以从所有可用的 Lendf.Me 流动性池中借到 10 多种资产(资产总值为 25,236,849.44 美元)。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程根本原因分析
我们通过研究源代码发现,“transferFrom()”操作的“from”地址注册成为“implementer”(通过标准化 ERC1820 界面)时调用“tokensToSend()”函数的内在逻辑就是事件涉及的漏洞所在。为了清晰展示,我们在“tokensToSend()”函数被调用时对部分代码进行截图如下所示。就如在 1054 行显示的那样,ERC1820 的“getInterfaceImplementer()”被用来收回已注册的 implementer。该函数有两个参数:“from”和“TOKENS_SENDER_INTERFACE_HASH”,第一个参数其实是攻击者参数(比如该参数可以向 Lendf.ME 提供 imBTC),而第二个参数是一个常数,即“keccak256("ERC777TokensSender")”。在 1056 行的代码中,“implementer”中定义的“tokensToSend()”函数被调用了,这使得攻击者可以通过填入其他恶意执行代码来黑进相应交易。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程
正如 OpenZeppelin 在 2019 年 4 月的帖子和去年 7 月发布的概念验证(proof-of-concept)漏洞所描述的那样,攻击者可以通过“InterfaceImplementer()”与定义上文提到的“tokensToSend()”的智能合约设置钩子(hook)。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程在“tokensToSend()”函数中,攻击者可以填入其他的逻辑代码,比如多次出售相同规模的 Token。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程
Uniswap 攻击事件
由于前面已经介绍了 Uniswap 攻击事件背后的理论,所以我们在这篇博客中不再赘述。本文中我们研究了一个特定的恶意交易:(hash: 0x9cb1d93d6859883361e8c2f9941f13d6156a1e8daa0ebe801b5d0b5a612723c1)。显然内嵌的“tokenToEthSwapInput()”又被调用了一次,这意味着攻击者又进行了一次将 imBTC 兑换成 ETH 的交易(当兑换比率被攻击者操纵至对其有利的水平时)。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程Lendf.Me 攻击事件
针对于 Lendf.ME 的黑客事件作用机制有所不同,但是本质上是一样的。如果我们研究下以下恶意交易:(hash: 0xae7d664bdfcc54220df4f18d339005c6faf6e62c9ca79c56387bc0389274363b),由于在存入函数中,Lendf.Me 中的“supply()”函数被嵌入一个额外的提现(withdraw())函数钩子(hook),这导致攻击者可以在不实际存入资产的情况下,伪造其 imBTC 抵押品余额的内部记录。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程
攻击者确实首先向 Lendf.Me 提供了确定数量的 imBTC (即 289.999999999 imBTC)。然而在第二个“supply()”中,攻击者仅实际提供了 0.000000001 个 imBTC,并且其后来通过“withdraw()”的钩子又取出了 290 imBTC (攻击者黑入了“dotransferIn()”中“imBTC:transferFrom()”的调用——1583 行)。从而使得 290imBTC 在钩子函数“withdraw()”中从攻击者的余额中成功扣除。然而,当代码又回执至“supply”时,余额又被重置为 290imBTC (1599 行)。这就是攻击者如何在 lendf.Me 中操纵 imBTC 抵押品余额数量的内在逻辑。通过多次上述操作,攻击者将其在 Lendf.Me 中的 imBTC 内部记录刷到了足够从多个流动池(总资产价值为 25,236,849.44 美元)中借出可用的 10 多种资产。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程
缓解措施
作为阻止这种重入攻击的缓解机制,Checks-Effects-Interactions 确实能够在这两个事件中起到帮助。如果 Lendf.Me“supply()”在存储用户的代币余额更新后调用“doTransferIn()”,攻击者就不可能通过调用“withdraw()”重置余额记录。
从另一角度分析,ERC777 原生地支持钩子(hook)机制的运行,因此我们需要防止其所有交易类型的重入攻击。比如,如果“supply()”和“withdraw()”都在函数起始部分设有互斥锁,那么攻击者就不可能使用“supply()”中的“withdraw()”。最后但同样重要的是,我们需要重新回顾一下在 ERC20 与 ERC777 之间进行选择时,选择 ERC777 正是考虑到其能更好的保护用户资产(因为每次交易操作时,不需要用户将所有的 Token 都授权给平台)。
写在最后
Lendf.Me 黑客事件对于当前的 DeFi 社区而言确实是一个打击。在下面的图片中我们收集了在该事件中各项资产的损失额数据。
硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

PeckShield 作者 子铭 翻译

Edward 编辑

内容仅供参考 不作为投资建议 风险自担

版权所有 未经允许 严禁转载

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

硬核解析 Uniswap 与 Lendf.Me 攻击全过程

☟☟☟


声明:本内容为作者独立观点,不代表 CoinVoice 立场,且不构成投资建议,请谨慎对待,如需报道或加入交流群,请联系微信:VOICE-V。

评论0条

加密谷Live

简介:分享区块链领域专业、前沿、有趣的内容

专栏

更多>>