分类
Uncategorized

创宇区块链实验室 | Harvest.finance 闪电贷攻击事件

 

创宇区块链安全实验室 水手 2021-04-20 14:50:41 发布在 区块链社区

8004 1

前言

前不久,DeFi 项目 Harvest.finance 遭受黑客攻击,黑客利用闪电贷套利 2400 万美元,涉及金额巨大,轰动一时

知道创宇区块链安全实验室  旨在通过全盘梳理攻击流程和代码细节,一窥闪电贷套利的秘密。

全盘梳理

基础信息

攻击者地址:0xF224ab004461540778a914ea397c589b677E27bb
攻击合约地址:0xc6028a9Fa486F52efd2B95B949AC630d287CE0aF
首次攻击 tx:0x35f8d2f572fceaac9288e5d462117850ef2694786992a8c3f6d02612277b0877
VaultProxy(fUSDC):0xf0358e8c3CD5Fa238a29301d0bEa3D63A17bEdBE
CRVStrategyStableMainnet:0xD55aDA00494D96CE1029C201425249F9dFD216cc
VaultYCRV:0xF2B223Eb3d2B382Ead8D85f3c1b7eF87c1D35f3A
CRVStrategyYCRVMainnet:0x2427DA81376A0C0a0c654089a951887242D67C92
convertor:0xfCA4416d9dEF20aC5b6Da8b8b322b6559770eFbF
*为方便起见,后面提到的地址均只用地址前 4 位代表

交易始末

从 tx0x35f8 中的代币转移记录中可以大致看出事件经过

详细的合约调用过程可通过以太坊交易分析平台载入交易 hash 进行分析

流程分析大致如上,事件概括起来即是攻击者 0xf224 部署了攻击合约 0xc602,然后一系列闪电贷攻击均在攻击合约的 0xfdb57542 方法中进行,其中核心流程就是通过 Uniswap 的 Flash Swap 进行闪电贷,先获得大量 USDT 和 USDC 为后续攻击做准备,然后重复执行如下动作:

  1. Curve ySwap 中进行 USDT=>USDC 的巨额兑换(巨额兑换造成 y 池中 USDC 价格上涨)
  2. USDC 质押存入 VaultProxy fUSDC 池( USDC 价格上涨,铸造出较平常更多的 fUSDC )
  3. Curve ySwap 进行 USDC=>USDT 回兑(1 步骤的逆操作,USDC 价格恢复)
  4. VaultProxy fUSDC 池中赎回 USDC ( USDC 价格回落,赎回出较平常更多的 USDC )

最后归还闪电贷并将获利的 USDC 兑换为 ETH 提取

代码细节

攻击合约未开源,暂时不作分析。可先从关键的 VaultProxy fUSDC 池合约 0xf035 的 deposit 函数入手,分析 fUSDC 的铸造量是如何计算的

从质押函数中可以看出 fUSDC 的铸造量是根据 fUSDC 总量和 USDC 策略的总投资量的比例来决定的

underlyingBalanceWithInvestment 函数实现如下:

fUSDC 池代理合约 0xf035 会进一步调用 CRVStrategyStableMainnet 策略合约 0xD55a 去进一步查询已投资的底层资产 USDT 的量

来到稳定币策略合约 0xD55a,investedUnderlyingBalance 函数实现如下:

这里的调用就稍微复杂一点了,从 ycrvVault 合约 0xF2B2 获取 shares 与 price,将乘积传入 underlyingValueFromYCrv 函数,结果与该合约 USDT 的量的和作为最后的函数返回值

我们先来看 ycrvVault 合约 0xF2B2

该金库合约 0xf2b2 本身继承了 ERC20,具有代币属性,从构造函数中可以看出代币代表 fyToken

也就是说上面获取的 shares 即是策略合约拥有的 fyToken 量

然后是 price,来看 getPricePerFullShare 函数:

可以明显看出 price 即是 yToken 对 fyToken 的占比,那么 shares 与 price 的乘积即代表策略合约所占有的 yToken 量,最后传入 underlyingValueFromYCrv 函数,在该函数中会调用 convertor.yCrvToUnderlying

这里就到了整个过程中最关键的地方了,也是问题的根本所在

convertor 合约 0xfCA4 并未开源

我们再次回到以太坊交易分析平台,查看整个 deposit 调用过程

可以看到前面的调用流程分析如实,并且 convetor 的调用最终会调用 Curve 的 Zap.calc_withdraw_one_coin,而该函数用于查询 lpToken 的赎回价

问题就在这里了,这里相当于就是向 Curve 问价,而调用传入的是 yToken 的量,那么返回的就是 yUSDC 兑换 USDC 的价格,即 USDC/yUSDC

而当前面巨额兑换 USDC 后,y 池中 USDC 价格上涨,那么相对价格 USDC/yUSDC 就会下跌。Harvest.finance 的 USDC 策略中 yUSDC 资产所具有的 USDC 净值经 calc_withdraw_one_coin 计算而来就损耗减少,最终反映到 deposit 函数的 fUSDC 铸造算法中,将导致 fUSDC 铸造量增加


总结

归根到底,Harvest.finance 被攻击的本质原因在于对策略稳定币价值的估价出现了问题,直接调用易被操纵价格的 Curve 的 calc_withdraw_one_coin 函数来估价,从而使攻击者有机可乘。这就是一次典型的喂价机制不完善导致的价格操纵的经济攻击事件。

知道创宇区块链安全实验室官网:www.knownseclab.com
知道创宇唯一指定存证平台www.attest.im
联系我们:blockchain@knownsec.com



知道创宇区块链安全实验室导航


微信公众号
@ 创宇区块链安全实验室

微博
@ 知道创宇区块链实验室
https://weibo.com/BlockchainLab


知乎
@ 知道创宇区块链安全实验室
https://www.zhihu.com/org/zhi-dao-chuang-yu-qu-kuai-lian-an-quan-shi-yan-shi


Twitter
@KS_Blockchain_
https://twitter.com/KS_BlockchainWeb

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注