Uniswap的ERC777重入风险详解

Uniswap的ERC777重入风险详解-1

背景

2020 年 4 月 18 日,Tokenlon 宣布暂停 imBTC 转账,原因是发现攻击者利用 Uniswap 流动性合约中的 ERC777 重入漏洞对 ETH-imBTC 矿池周期进行套利。这次的攻击手段是Uniswap v1.0上存在的一个已知漏洞。该漏洞最早由Consensys于2019年4月发现,当时Consensys只是发现了该风险,尚未找到可以利用该方法进行攻击的token。后来imBTC上线Uniswap后,由于imBTC是基于ERC777实现的,结合ERC777的特点和Uniswap代码存在的问题,攻击者可以通过重入漏洞实现套利。接下来,我们将在未来分析这种套利的攻击方式和具体细节。

前置知识

ERC777协议是以太坊上的代币标准协议。该协议是以太坊上 ERC20 协议的改进版本。主要改进如下:

1.使用与发送以太币相同的概念发送token,方法为:send(dest, value, data)

2、合约和普通地址都可以通过注册tokensToSend钩子函数来控制和拒绝发送哪些token(拒绝发送是通过钩子函数tokensToSend中的revert实现的)

3. 合约和普通地址都可以通过注册tokensReceived钩子函数来控制和拒绝接受哪些token(拒绝接受是通过钩子函数tokensReceived中的revert实现的)

4.tokensReceived可以通过hook函数在一笔交易中发送代币和通知合约接受代币,不像ERC20需要通过两次调用(approve/transferFrom)完成

5. 持有人可以“授权”和“撤销”运营商(运营商:可以代表持有人发送代币)这些运营商通常是(去中心化的)交易所、支票处理商或自动支付系统

6.每笔代币交易包含data和operatorData字段,可以分别传递持有者和运营者的数据

7. 可以部署一个实现了tokensReceived的代理合约来兼容没有实现tokensReceived功能的地址

这里,需要特别注意第二点,ERC777标准中的tokenToSend函数。根据ERC777协议的定义,遵循该标准的代币在每次发生代币转账时都会尝试调用代币发送方的tokensToSend函数,代币持有者可以在ERC1820注册合约中注册自己的合约,部分进程在通过在这个钩子函数中定义一些操作来处理令牌传输过程,例如拒绝令牌发送或其他操作。

了解这些关键点,有助于我们理解此次攻击的具体攻击方式。从现在开始,我们可以稍微提速一下,看看这次Uniswap发生了什么?

详细分析

通过 Etherscan 查询攻击者的一笔交易 0x32c83905db61047834f29385ff8ce8cb6f3d24f97e24e6101d8301619efee96e

Uniswap的ERC777重入风险详解-2

可以发现,攻击者两次将imBTC转入Uniswap合约,金额相同,均为0.00823084,随后又从Uniswap收到两笔ETH,看似很正常的两笔交易,实则暗流涌动等玄机。为了更好的了解整个交易的细节,我们需要通过bloxy.info查看交易的具体细节。

Uniswap的ERC777重入风险详解-3

通过查询交易明细,我们发现攻击者首先通过ethToTokenSwapInput函数将一些imBTC换成Uniswap,然后通过tokenToEthSwapInput函数将imBTC第一次换成ETH,然后Uniswap先将ETH转给攻击者,然后调用imBTC的transferFrom函数,由于imBTC实现了ERC777标准,在调用imBTC的transferFrom函数时,imBTC会调用攻击者的tokensToSend函数。然后,在攻击者的tokensToSend函数中,攻击者将第二次用imBTC换取ETH,流程结束。

从交易的细节来看,这里似乎没有问题,我们继续追踪UniSwap的代码。

Uniswap的ERC777重入风险详解-4

上面的代码是Uniswap的ethToTokenSwapInput函数的代码。根据代码分析,Uniswap的ethToTokenSwapInput函数会调用ethToTokenInput函数,然后先通过getInputPrice获取可以兑换token的eth数量,然后通过send函数将eth发送给用户,最后将token转入通过 transferFrom 签约。让我们转到 getInputPrice 函数。

Uniswap的ERC777重入风险详解-5

通过分析getInputPrice函数,我们可以知道获取ETH数量的计算公式为

Uniswap的ERC777重入风险详解-6

将此公式放在 ethToTokenInput 函数的上下文中,公式变为

Uniswap的ERC777重入风险详解-7

在这个公式下,在正常的imBTC兑换ETH的过程中,作为分母的imBTC储备在兑换后应该会增加,对应的ETH储备会减少。

Uniswap的ERC777重入风险详解-8

但是回顾攻击者的操作方式,当攻击者第一次将imBTC发送给ETH时,Uniswap会先将ETH发送给攻击者。此时Uniswap中的ETH储备减少,然后Uniswap调用transferFrom函数,(注意此时攻击者的imBTC还没有被扣除),然后当攻击者在transferFrom函数中第二次调用ethToTokenSwapInput时,通过getInputPrice获取兑换的ETH数量的公式会变成这样:

Uniswap的ERC777重入风险详解-9

注意在第二次兑换计算中,只有ETH的储备减少了,而imBTC的储备并没有增加,这导致相比于单独调用ethToTokenSwapInput函数,攻击者可以在使用imBTC兑换的过程中ETH第二次,计算公式的分子变了,但是公式的分母不会变。与正常兑换相比,攻击者通过重入方式进行的二次兑换会获得少量收益,从而实现盈利。重复这个过程,通过同样数量的 imBTC 可以获得更多的 ETH,导致 Uniswap 业务经营者的亏损。

防御方法

1、在Uniswap的tokenToEthSwapInput函数中加入OpenZeppelin的ReentrancyGuard函数来防止重入。

2. 进行代币兑换时,先扣除用户的代币,再将ETH发送给用户。

同时,针对本次攻击,慢雾安全团队建议:

1、关键业务操作方法增加锁机制,如:OpenZeppelin的ReentrancyGuard

2. 开发合约时,采用先改变这个合约的变量,再进行外部调用的写法

3、项目上线前,邀请优秀的第三方安全团队进行全面的安全审计,尽可能发现潜在的安全问题

4. 多个合约对接时,还需要检查多方合约的代码安全和业务安全,充分考虑各种业务场景组合下的安全问题

5. 合约应尽可能设置暂停开关,以便在“黑天鹅”事件发生时及时发现并止损

6、安全是动态的,各项目方也需要及时捕捉可能与自身项目相关的威胁情报,及时排查安全隐患

关于慢雾

慢雾科技是一家区块链安全公司,成立于2018年1月。该公司由拥有超过十年网络安全经验的团队创立,成为一支全球性的力量。我们的目标是让区块链生态系统对每个人都尽可能安全。我们现在是一家知名的国际区块链安全公司,曾参与过火币、OKX、Binance、imToken、Crypto.com、Amber Group、Klaytn、EOS、1inch、PancakeSwap、TUSD、Alpaca Finance、MultiChain、 O3Swap等

网址:https://www.slowmist.com推特:https://twitter.com/SlowMist_TeamGithub:https://github.com/slowmist/

提示:投资有风险,入市需谨慎,本资讯不作为投资理财建议。请理性投资,切实提高风险防范意识;如有发现的违法犯罪线索,可积极向有关部门举报反映。
你可能还喜欢