冰棒金融安全事件分析

攻击流程揭秘:攻击者利用Popsicle Finance的步骤

冰棒金融安全事件分析

2021年8月4日,Popsicle Finance 在一次攻击中遭受了巨额财务损失(超过2000万美元)[1]。 经过手动分析,我们确认这是一次“重复领取”攻击,即其奖励系统中的一个漏洞允许攻击者反复领取奖励。 在下文中,我们将使用一次攻击交易来阐述攻击过程和漏洞的根本原因。

背景

Popsicle Finance 是一个收益优化平台,支持多个链(例如以太坊和 BSC)的多个金库。

具体来说,用户首先调用deposit函数提供流动性,并获得Popsicle LP代币(简称PLP)。之后,Popsicle Finance将为用户管理流动性(与Uniswap等平台交互)以赚取利润。 用户可以调用withdraw函数从Popsicle Finance取回流动性,Popsicle Finance将根据PLP代币的数量计算应返还的金额。 激励奖励来自流动性,会随着时间的推移而累积。 用户可以调用collectFees函数来领取奖励,这是本次攻击的关键。

漏洞分析

collectFees函数中,会为用户计算token0Rewardtoken1Reward(对应LP代币对的奖励)。整个计算逻辑很简单。然而,该函数使用了一个名为updateVault的修饰符,用于相应地更新奖励。

简而言之,updateVault会:

  1. 首先调用_earnFees函数从池中获取累积费用;
  2. 然后调用_tokenPerShare函数更新token0PerShareStoredtoken1PerShareStored,它们表示池中每份代币0和代币1的数量;
  3. 最后调用_fee0Earned_fee1Earned函数更新用户的奖励(即分别为token0Rewardstoken1Rewards)。

_fee0Earned_fee1Earned函数具有相同的逻辑,即实现以下公式(以代币0为例):

user.token0Rewards += PLP.balanceOf(account) * (fee0PerShare - user.token0PerSharePaid) / 1e18

请注意,计算是增量式的,这意味着即使用户不持有PLP代币,计算出的奖励仍然是存储在token0Rewards中的值。

因此,我们可以得出以下两点观察:

  1. 用户的奖励存储在token0Rewardstoken1Rewards中,它们与任何PLP代币无关
  2. collectFees函数仅依赖于token0Rewardstoken1Rewards的状态,这意味着可以在不持有PLP代币的情况下提取奖励

在现实场景中,这意味着用户将钱存入银行,银行给她一张存款证明。不幸的是,这张证明既不防伪,也不与用户关联。 在这种情况下,可以制造假证并将其分发给他人,从而从银行获利。

攻击流程

简而言之,攻击者采取了以下步骤发动攻击:

  1. 创建了三个合约。其中一个用于发动攻击,另外两个用于调用collectFees函数获取奖励;
  2. 利用闪电贷,即从AAVE借入大量流动性;
  3. 发动了存款-提款-领取奖励循环来执行攻击(总共有8个循环,大量流动性已从Popsicle Finance的多个金库中提取);
  4. 将闪电贷归还给AAVE,并通过Tornado.Cash洗钱。

具体来说,存款-提款-领取奖励循环由几个步骤组成,使用我们的在线工具 [2]可以轻松标记和清晰总结:

利润分析

总计,攻击者从Popsicle Finance中攫取了2000万美元,包括2.56K WETH、96.2 WBTC、160K DAI、5.39M USDC、4.98M USDT、10.5K UNI。 在这次利用之后,攻击者首先通过Uniswap和WETH将所有其他代币兑换成ETH,然后使用Tornado.Cash进行了洗钱。

鸣谢

Yufeng Hu, Ziling Lin, Junjie Fei, Lei Wu, Yajin Zhou @BlockSec

(按姓氏字母顺序排列)

https://www.blocksecteam.com

Medium: https://blocksecteam.medium.com/

Twitter: https://twitter.com/BlockSecTeam

联系方式: [email protected]

参考

[1] https://twitter.com/defiprime/status/1422708265423556611

[2] https://tx.blocksecteam.com/

Sign up for the latest updates