mt logoMyToken
总市值:
0%
恐慌指数:
0%
币种:--
交易所 --
ETH Gas:--
EN
USD
APP
Ap Store QR Code

Scan Download

Cream Finance 安全事件深度分析

收藏
分享

2021年8月30日, Cream Finance 遭受攻击,损失超过1000万美金。对于本次安全事件,网上已经有一些分析指出这是一次利用闪电贷的重入攻击。然而这些分析仅针对攻击交易本身,其中还存在一些问题尚未厘清,比如这一次的重入攻击与先前的经典重入攻击有何区别,攻击者为什么通过清算获利等。对这些问题的背后原因进行探究,有助于帮助我们更好地理解该类DeFi安全威胁,并采取应对措施。

问题1:本次重入攻击和之前的重入有什么核心不同点?重入漏洞的本质究竟是什么?

Cream合约的漏洞成因仍然是重入,但是本次重入的最核心问题是多合约之间的重入。我们认为重入漏洞中的重入其实是在描述利用方式,而非刻画漏洞本质。重入漏洞究其本质可以建模成risky access,即:a)存在着某一个共享的状态;b)存在着至少两个操作可通过external function改变共享的状态;c)至少一个操作是写操作。在满足上述条件的情况下,我们认为存在着一个risky access。而在这样的定义下,共享的状态可以在出现在同一个函数,同一个合约,甚至是不同的合约。而如何利用这样的risky access来发起攻击,就需要进行重入了(通过重入实现第二个条件)。

问题2:攻击者通过攻击获得的 AMP token,如何实现套现获利?

攻击者通过重入获得是AMP token和一部分亏空的ETH,攻击者需要将AMP token套现来获得盈利和还掉闪电贷。攻击者可以选择多种方式进行,比如在DEX中用AMP token换取ETH和在Cream中进行清算两种方式套现。这两种套现的方式各有利弊。我们认为清算是一种获利方式更高的套现手段,可以避免大量在DEX中用AMP token换取ETH引起的价格波动和滑点。

问题3:还有哪些链上机制被攻击者利用实施攻击?

我们发现本次攻击中,FlashBot被攻击者滥用以贿赂旷工,从而获得快速上链权。对于FlashBot的安全隐患,我们曾经在之前发布的文章中进行过讨论(具体可参考由xSNXa事件引发的对FlashBot的思考),而本次攻击事件进一步证实了FlashBot对于区块链生态的安全影响,需引起重视并引入机制来对FlashBot交易进行管理。正如菜刀,用来切菜是无害的,用来行凶则成为作案工具。

以下我们将围绕上述三个问题,从多合约重入、套现获利方式和FlashBot被滥用三个角度对本次攻击开展深度分析。

0x1. 多合约重入

ERC777标准相比 ERC20 ,包装了诸多特性,其中之一便是:一笔转账过程中引入两次回调,分别在余额增加前后(TokensToSend, TokensReceived)。具体实现机制是使用了 ERC1820 标准的注册机制,转账相关合约如果实现了相应的接口函数并在ERC1820合约中注册过,便会在转账发生时,分别去调用代币减少一方 (Holder) 的 TokensToSend 函数和代币增加一方 (Receiver) 的 TokensReceived 函数。

重入攻击是由于某些不可信的外部调用,打断了一些原子性的事务 (比如转账和记账),造成变量状态不一致而产生的。

对于一般的ERC20代币,在转账的过程中是不涉及外部调用的。我们可以假设不会影响合约的状态,但是对于ERC777这一假设便不成立了。因此很多DeFi协议由于引入ERC777代币,而造成严重的安全事故(比如: Uniswap V1, Lendf.Me等)。

0x1.1 攻击形式和逻辑变得日益复杂

随着Defi生态的不断成熟繁荣的同时,我们也可以看到,攻击的形式与逻辑也越来越复杂。

以重入攻击为例:从最初比较简单的在函数转账后重入转账函数,导致最终记账结果不正确(比如:The DAO, Lendf.Me事件)。现在大部分的合约都会采用锁的机制(nonReentrant等)来避免。到利用转账前后计价公式中间状态的不一致**,重入获利(比如:UniswapV1)。

但是,这种锁的机制真的可以一劳永逸吗?事实并非如此。nonReentrant 可以保证函数以及合约层面无法被重入,但是对于依赖关系复杂的 Defi 协议,一个变量并非仅仅影响一个合约。这时,原本存在重入攻击可能的地方,即使有了 nonReentrant 的保护,我们是否也可以采用一种声东击西的方式。来在其他依赖该变量的地方做一些手脚呢?本次的事件也是如此。

0x1.2 具体代码解读

可以看到,用户从Cream借钱时的函数调用大致为:

borrow → borrowInternal → borrowFresh

在最内层的 borrowFresh中,我们可以看到,这似曾相识的代码,便是一年之前,Lendf.Me倒下的地方。

在 Transfer 前会使用临时变量vars记录转账后的一些结果,transfer 结束后再更新到借贷池的全局状态变量中。

虽然Cream吸取了前辈的教训,在这个函数中使用了 nonReentrant,这保证了该借贷池的合约是无法被重入的。但是,遗憾的是,一个交 易池 交易池的状态,并不仅仅关系到自己。

代码中我们可以看到,在进入borrowFresh前,会先调用 borrowAllowed函数,判断用户是否有资格进行借款。这一资格指的是用户的账务情况。如果用户账面有足够的流动性,便可以借出相应数量的资产。而这一流动性并不仅仅是用户在一个借贷池中的借贷情况,而是用户在 Cream 平台全部借贷池中的累计:

 

 

可以看到borrowAllowed调用了getHypotheticalAccountLiquidityInternal函数来计算用户的流动性,看用户是否已经资不抵债。

在getHypotheticalAccountLiquidityInternal中,会遍历用户所在的不同借贷池,通过 getAccountSnapshot函数,获得用户借出的底层资产 (Underlying Token) 数量。这样,利用ERC777重入导致用户其中一个借贷池状态未更新。便可以实现「我借了,但我就说我没借」这样一种效果,实现超额借贷。

重入攻击的流程如下:

Step 1: 利用 Flash Swap 从 Uniswap 借出 500 ETH

Step 2: 将借出的 ETH 抵押到 Cream,调用crAMP池中的borrow函数,换取全部抵押ETH价值45%数量的AMP token(19,480,000,000,000,000,000,000,000)

注意!到这一步,用户在Cream已经没有流动性,本不应再借出任何代币,但是由于crAMP池中用户的借贷状态尚未更新,使得用户在外部调用中还拥有全部的流动性。

Step 3:在AMP transfer的回调函数中,调用crETH池中的borrow函数,再次换取全部抵押ETH价值75%数量的ETH (355 ETH)

 

 

可以看到,这一步攻击者获得了原抵押物45% + 75% = 120%价值的代币。

0x2. 获利处理

我们在上一步重入攻击中已经产生了获利,但是获利一部分是AMP token,此时的持有的ETH是不足以还上UniswapV2的闪电贷的,那么怎么才能将AMP套现获得足够的ETH?

方法1:还crETH或者crAMP的借款,从而取出一开始的抵押物ETH。但是由于在重入攻击结束之后,同时修改了crETH和crAMP两个合约的状态。一旦需要还款取出全部抵押物,Comptroller会在检查这两个合约的借账清零后再同意。这将导致所有重入的获利重新回到Cream.Finance手上,因此是不行的。这也是攻击者为什么不直接偿还借贷来获利的原因。

方法2:将获得的AMP token在去中心化交易所(如Uniswap)换成ETH。这种做法是可行的,而且事实上攻击者其中几笔攻击交易中确实采取了这种做法(详见下文表格)。但是这种做法有个缺陷,由于攻击获得的AMP的量较大,而大量的AMP token流进Uniswap池子会导致滑点(即用同样的AMP token换出来的ETH量减少),导致攻击获利减少。

方法3:新建一个地址,用该地址清算实施重入攻击的攻击者的负债。由于Cream Finance的清算实现中,其清算折扣是一个固定值(即清算者能以一定的折扣购买到抵押品,见图中清算所得的计算),且只要超额抵押率低于某一定值就可以执行。而在上一步重入攻击之后,由于攻击者借出的ETH和AMP两种资产的总价值超出了抵押的ETH的价值,这个时候满足了清算条件。所以新建的地址可以以一定的折扣获得前面攻击地址的部分抵押物,即ETH(通过redeem crETH)。该方法不仅没有去中心化交易所的滑点问题,还由于清算折扣的存在增加了攻击获利。但是能清算的资产是由一个最大额度(50%),这也是我们在攻击中最后看到攻击者只用了一半的AMP进行了清算(具体的清算逻辑可参考 liquidateCalculateSeizeTokens)。

0x3. FlashBot被滥用

FlashBot机制使得矿工可以将快速上链的机会进行拍卖,从而避免套利者之间的竞争导致的以太坊网络拥塞和交易费上升,其在套利者和矿池之间找到了利益的平衡点,因此被矿池大量采用。然而,FlashBot的出现也导致了另外的问题,即被攻击者利用将攻击交易快速上链,使得矿工成为攻击者的帮凶。我们对本次攻击的攻击者进行了详细的统计,我们发现将近一半的攻击交易是FlashBot交易。另外,我们也发现攻击是由两个攻击者发起,攻击总获利超过5800ETH,详细信息见下面表格。

攻击者

交易

是否为

Flashbot交易

获利方式

获利

0x8036ebd0...

0xc90468d6...

否用借出AMP总量的一半进行清算,剩下一半取出

9,740,000 AMP,

36.9945 ETH0x3ab23685...否将第二批攻击获得的AMP在 1inch 交易所兑换为ETH-9,740,000 AMP, 131.6135 ETH

0xce1f4b4f...

0x00167456...否

在Uniswap兑换部分AMP,其余取出

2,246,331 AMP0x77e2d72b...否在Uniswap兑换部分AMP,剩下的直接取出16,564,396 AMP0x55692ccc...是(攻击者可能利用了Flashbot)在Uniswap兑换部分AMP归还Flash Loan,其余取出18,198,820 AMP0x51fd8340...是(攻击者可能利用了Flashbot)在Uniswap兑换部分AMP归还Flash Loan,其余取出12,626,794 AMP0xf5a3225f...是(攻击者可能是Front-running受害者)在Uniswap兑换部分AMP归还Flash Loan,其余取出11,759,107 AMP0x8b4ec34b...是(攻击者可能利用了Flashbot)在Uniswap兑换部分AMP归还Flash Loan,其余取出16,016,121 AMP0xcb16bb40...是将第一批攻击获得的AMP在1inch交易所兑换为ETH-77,411,571 AMP, 887.0617 ETH0xba468e26...是(攻击者可能利用了Flashbot)在Uniswap兑换部分AMP归还Flash Loan,其余取出1,397,977 AMP0xd7ec3046...否用借出AMP总量的一半进行清算,剩下一半取出19,480,000 AMP, 69.5827 ETH0x487364b6...否用借出AMP总量的一半进行清算,剩下一半取出38,960,000 AMP, 148.7233 ETH0x6f3bc128...是(攻击者可能利用了Flashbot)用借出AMP总量的一半进行清算,剩下一半取出77,920,000 AMP, 297.4470 ETH0xf0f6a07e...是(攻击者可能利用了Flashbot)用借出AMP总量的一半进行清算,剩下一半取出77,920,000 AMP, 297.4472 ETH0x5452e5ff...是(攻击者可能利用了Flashbot)用借出AMP总量的一半进行清算,剩下一半取出38,960,000 AMP, 148.7240 ETH0x6afb3e8e...否用借出AMP总量的一半进行清算,剩下一半取出38,960,000 AMP, 148.7243 ETH0x1c346413...是(攻击者可能利用了Flashbot)用借出AMP总量的一半进行清算,剩下一半取出19,480,000 AMP, 78.2063 ETH0x1d20ea65...否用借出AMP总量的一半进行清算,剩下一半取出19,480,000 AMP, 78.2065 ETH0xa9a1b8ea...是(攻击者可能利用了Flashbot)用借出AMP总量的一半进行清算,剩下一半取出9,740,000 AMP, 41.0334 ETH0x7df47235...否将第二批攻击获得的AMP在1inch交易所兑换为ETH-102,297,977 AMP, 1,164.8246 ETH0xc464fed4...否将第二批攻击获得的AMP在1inch交易所兑换为ETH-100,000,000 AMP, 1,083.1151 ETH0xe15324ef...否将第二批攻击获得的AMP在1inch交易所兑换为ETH-140,000,000 AMP, 1,282.6449 ETH

攻击者0x8036ebd0总计获利168.608 ETH;攻击者0xce1f4b4f总计获利5725.741 ETH。

0x4. 结语

通过对Cream Finance安全事件的总结,我们对于该类安全威胁有了更深入的理解:重入问题最本质的原因在于对共享状态的risky access,形式可以是同一个合约的同一个函数,同一个合约的多个函数甚至是不同合约的函数,因此单纯依赖nonReentrant锁机制不能防止重入攻击,需要对合约逻辑层面的状态变化进行精确的分析和安全审计。

FlashBot对于生态的影响值得重视:Flashbot可能被滥用于攻击交易快速上链,成为攻击者的帮凶。这需要FlashBot服务提供者、矿工和安全社区的协作,构建DeFi生态安全共同体。

免责声明:本文版权归原作者所有,不代表MyToken(www.mytokencap.com)观点和立场;如有关于内容、版权等问题,请与我们联系。