LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 新闻观点 > Uniswap/Lendf.Me黑客事件: 根源和损失分析

Uniswap/Lendf.Me黑客事件: 根源和损失分析

2020-04-21 区块链研究员 来源:区块链网络


始于2020年4月18日上午12:58:19+UTC,DeFi平台Uniswap被黑客利用重入式漏洞攻击。大约24小时后,在4月19日上午12:58:43分+UTC,Lendf.Me也发生了类似的黑客攻击。从技术上看,这两起事件背后的主要逻辑是ERC777和那些DeFi智能合约不兼容,这会被攻击者误用,彻底劫持正常交易并进行额外的非法操作。

具体来说,在Uniswap黑客事件中,攻击者利用这个漏洞,将Uniswap的流动性池中的ETH-imBTC(约有1278个ETH)耗尽,而在Lendf.Me黑客中,攻击者利用这个漏洞(任意)增加了攻击者内部记录的imBTC抵押品金额,以便她可以从所有可用的Lendf.Me流动性池中借到(实际上是借到)10种以上的资产(资产总值2523649.44美元)。

同时,我们还需要注意的是,ERC777本身是一个社区建立的通根标准,它的高级功能适用于各种场景。但是,这些高级功能可能与某些DeFi场景不兼容。更糟糕的是,这种不兼容可能会进一步导致不良后果(例如,重入性)。我们还注意到,其他通根标准(如ERC1155)也有类似的callback功能。话虽如此,我们对imBTC ERC777实现的人工审查表明,它确实遵循了ERC777标准。


图1:与ERC777兼容的transfrom()

根源分析

如果我们深入到ERC777源码中,漏洞在于当transformationFrom()操作的from地址注册了自己为implementer(通过标准的ERC1820接口)时,调用tokensToSend()函数的内部逻辑。为了说明问题,我们在下面的代码片段中展示了调用tokensToSend()函数时的上下文。特别是,如第1054行所示,ERC1820的getInterfaceImplementer()函数用于获取注册的实现者(如果有的话)。这个特殊的函数需要两个参数,from和toKENS_SENDER_INTERFACE_HASH:第一个参数基本上是攻击者(例如,向Lendf.Me提供imBTC的地址),第二个是一个常数,即keccak256("ERC777TokensSender")。之后,在第1056行,在实现器中定义的tokensToSend()函数被调用,这使得攻击者可以通过本质上注入额外的恶意代码来劫持交易执行。


图2: ERC777兼容的tokensToSend() 劫持

正如OpenZeppelin在2019年4月的帖子和去年7月发布的概念验证漏洞中描述的那样,攻击者可以通过设置InterfaceImplementer()来用定义上述tokensToSend()的智能合约设置hook钩子。


图3:OpenZeppelin的Exploit演示(hook设置)

在tokensToSend()函数中,攻击者基本上可以执行额外的逻辑,例如,将同一批通根多次出售。


图4:OpenZeppelin的Exploit演示(hook功能)

Uniswap黑客

由于Uniswap黑客事件背后的理论已经在前一篇文章介绍过了,所以我们在这篇文章中不打算进一步阐述。相反,我们检查一个特定的恶意交易(哈希:0x9cb1d93d6859883361e8c2f9941f13d6156a1e8daa0ebe801b5d0b5a612723c1)。显然,里面嵌入了一个额外的tokenToEthSwapInput()调用。这意味着当转换率被操纵到攻击者的优势时,攻击者可以将另一批imBTC代币换成ETH。


图5:Uniswap黑客

Lendf.Me黑客

Lendf.Me黑客的工作原理略有不同,但性质仍然相同。如果我们检查一个特定的恶意交易(哈希:0xae7d664bdfcc54220df4f18d339005c6faf6e62c9ca79c56387bc0389274363b),Lendf.Me中的存款函数,即support()通过嵌入额外的 withdraw()操作被钩住,导致攻击者的imBTC抵押品金额的内部记录增加,而没有实际存入金额。


图6:Lendf.Me Hack

背后的逻辑是,攻击者确实在第一时间向Lendf.Me提供了一定数量的imBTC(例如289.9999999999999 imBTC)。然而,在第二次 supply()中,攻击者仅仅提供了 0.00000001 imBTC,但在钩子内还额外提供了 290 个 imBTC(通过劫持 doTransferin()内的 IMBTC::transferFrom() 调用--第 1583 行)。结果,290 imBTC被从内嵌的 withdraw()内的攻击者的余额中减去了290 imBTC。然而,当执行返回到support()时,余额被重置为290 imBTC(第1599行)。这就是攻击者在Lendf.Me中操纵攻击者内部记录的imBTC抵押品金额的方式。在抵押品金额足够大的情况下,攻击者因此可以从各种流动性池中借到所有可用的10种以上资产(资产总值为25,236,849.44美元)。


图7:Lendf.Me黑客详情

方法

作为一种常见的阻断此类重入攻击的缓解机制,所谓的检查Checks-影响Effects-交互Interactions设计模式总是有帮助的。例如,如果Lendf.Me的support()调用doTransferIn()保存用户更新token余额后,攻击者就不会有机会因为 withdraw()的调用而重置余额更新。

另一方面,由于ERC777的特性,不可避免地实现了挂钩机制,因此我们需要在所有的交易函数中防止重入。例如,如果support()和 withdraw()都试图在函数开始时持有一个mutex锁,那么坏的行为者就不能在support()的主体内执行 withdraw()。最后,我们可能需要重新审视一下ERC20和ERC777之间的选择,同时注意到选择ERC777的好处是方便保护用户的资产(因为每次交易操作无需用户批准对所有的平台上的通根交易进行操作)。

.

后果

Lendf.Me黑客对目前的DeFi社区是一个巨大的打击。下面让我们把这次事件中各种资产的损失金额放在一起。


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

作者:PeckShield

翻译:区块链Robin

BTC:1Robin84SWtzSxnU1v8CE9rzQtcfUsGeN
微信:chanhai13;公众号:链学园
译文有编辑及删减,如有侵权,请联系译者删除
中文版权所有,转载需完整注明以上内容

—-

编译者/作者:区块链研究员

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...