免责声明:金色财经所有资讯仅代表作者个人观点,不构成任何投资理财建议。请确保访问网址为(jinse.cn) 举报

    Popsicle Finance 双花攻击分析

    北京时间 2021 年 8 月 4 日早上 6 点(区块 12955063),Popsicle Finance 项目下的多个机枪池被攻击,损失金额超过两千万美元,是迄今为止 DeFi 领域发生的损失数额最大的单笔攻击之一。通过分析攻击交易及项目代码我们发现,此次攻击是一个利用项目的记账漏洞进行多次提取的攻击(Double-Claiming Rewards)。下面我们通过代码和攻击流程分析此次攻击。

    代码分析

    Popsicle Finance 是一个涉及多个链的机枪池(Yield Optimization Platform)。

    用户首先调用 deposit 函数向机枪池存入一定的流动性,并获得 Popsicle LP Token (以下简称 PLP Token)作为存款的份额证明。Popsicle Finance 会将用户提供的流动性存入 Uniswap 等底层池子并获得收益。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    用户还可以调用 withdraw 函数,根据用户持有的 PLP Token 所代表的流动性份额,从机枪池取回流动性。Popsicle Finance 会将 PLP Token 对应的流动性从 Uniswap 等底层池子中取回给用户。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    最后,用户在机枪池中存的流动性会随着时间产生一定的收益(Yield),会累计在合约的用户状态中。用户可以调用 collectFees 函数取回部分存款奖励。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    本次攻击的核心函数正是 collectFees 函数。下面我们逐步分析其代码。首先获得存储在 userInfo 中的用户状态。其中用户状态中的 token0Rewards 和 token1Rewards 是由于用户存款而累积的奖励。

    接下来计算该合约中,对应机枪池的 Token 对的 Balance。如果在合约中有足够的 Balance,就按金额将 Reward 支付给用户;否则会调用 pool.burnExactLiquidity 从底层 pool 取回流动性返回给用户。

    最后,会将记录在 userInfo 中的 Rewards 状态进行更新。看到这里,机枪池的代码实现还是比较符合逻辑的。但是在函数开头我们发现了 updateVault modifier,这个函数会在 collectFees 的函数体之前运行,漏洞也许在 updateVault 相关的函数中。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    以上是 updateVault 相关函数的实现。过程如下:

    • 首先调用_earnFees 向底层 pool 获取积累的 Fee;

    • 随后调用_tokenPerShare 更新 token0PerShareStored 和 token1PerShareStored 参数,这两个参数代表了池子中每个 share 代表的 token0 和 token1 的数量,即机枪池的每个份额计代表的 Token 对数量;

    • 最后调用fee0Earned 和fee1Earned 更新对应到这个用户的存款 Rewards (即 user.token0Rewards 和 user.token1Rewards)。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    以上是fee0Earned 和fee1Earned 函数的实现,两个函数实现相同,都实现了这样一个公式(以_fee0Earned 为例):

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

    也就是说,该函数会在原有的 user.token0Rewards 基础上,根据用户拥有的 PLP Token 数量计算应给用户发放的 Fee 的份额。

    但我们注意到这个函数是增量的,也就是说即使用户并没有持有 PLP Token (PLP.balanceOf(account) 为 0),该函数仍会返回保存在 user.token0Rewards 中记账的存款奖励。

    因此对于整个合约,我们发现两个重要的逻辑缺陷:

    • 用户的存款奖励是记录在 user.token0Rewards 和 user.token1Rewards 中的,并不与任何 PLP Token 或其他东西有任何形式的绑定。

    • 用于取回存款收益的 collectFees 函数仅仅依赖于记账的 user.token0Rewards 和 user.token1Rewards 状态,即使用户并未持有 PLP Token,仍可以取出对应的存款奖励。

    我们假想一个攻击流程:

    • 攻击者向机枪池中存入一定的流动性,获得一部分 PLP Token。

    • 攻击者调用 collectFees(0, 0),后者会更新攻击者的存款奖励,即状态变量 user.token0Rewards 的值,但并没有真正取回存款奖励。

    • 攻击者将 PLP Token 转给自己控制的其他合约,再调用 collectFees(0, 0) 更新状态变量 user.token0Rewards。也就是说通过不断地流转 PLP Token 并调用 collectFees(0, 0),攻击者复制了这些 PLP Token 对应的存款奖励。

    • 最后,攻击者从以上各个地址调用 collectFees 函数,取回真正的奖励。此时虽然这些账户中并没有 PLP Token,但由于记账在 user.token0Rewards 没有更新,攻击者因此得以取出多份奖励。

    用现实生活中的例子来描述这个攻击,相当于我向银行存钱,银行给了我一张存款凭证,但这张凭证没有防伪措施也没有和我绑定,我把凭证复印了几份发给不同的人,他们每个人都凭借这个凭证向银行取回了利息。

    攻击流程分析

    通过以上的代码分析,我们发现了 Popsicle Finance 在机枪池实现上的漏洞。下面我们对攻击交易进行深入分析,看攻击者是怎样利用这个漏洞的。

    攻击者的总体流程如下:

    • 攻击者创建了三个交易合约。其中一个用于发起攻击交易,另外两个用于接收 PLP Token 并调用 Popsicle Finance 机枪池的 collectFees 函数取回存款奖励。

    • 通过闪电贷从 AAVE 借出大量流动性。攻击者选择了 Popsicle Finance 项目下的多个机枪池,向 AAVE 借出了对应这些机枪池的六种流动性。

    • 进行Deposit-Withdraw-CollectFees循环。攻击者一共进行了8 次循环,分别攻击了 Popsicle Finance 项目下的多个机枪池,取出了大量流动性。

    • 向 AAVE 归还闪电贷,并将获利通过 Tornado Cash 洗钱。

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    本次攻击交易主要由数个 Deposit-Withdraw-CollectFees 循环构成,每一个循环的示意图如上图所示。根据我们的分析,逻辑如下:

    • 攻击者首先将闪电贷借来的流动性存入机枪池中,获得一定量的 PLP Token。

    • 攻击者将 PLP Token 转给攻击合约 2。

    • 攻击合约 2 调用机枪池的 collectFees(0, 0) 函数,设置合约 2 对应的 user.token0Rewards 和 user.token1Rewards 状态。

    • 攻击合约 2 将 PLP Token 转给攻击合约 3。

    • 和攻击合约 2 的操作类似,攻击合约 3 调用机枪池的 collectFees(0, 0) 函数,设置合约 2 对应的 user.token0Rewards 和 user.token1Rewards 状态。

    • 攻击合约 2 将 PLP Token 转回攻击合约,后者调用机枪池的 withdraw 函数 Burn 掉 PLP Token,取回流动性。

    • 攻击合约 2 和攻击合约 3 调用 collectFees 函数,用虚假的 tokenRewards 状态取回了存款奖励。

    根据我们的以太坊交易追踪可视化系统(https://tx.blocksecteam.com/)给出的交易调用图如下,其中部分重要交易用红字进行标注:

    [虚拟印钞机] Popsicle Finance 双花攻击分析

    利润分析

    本次攻击一共获利:2.56k WETH,96.2 WBTC,160k DAI,5.39m USDC,4.98m USDT,10.5k UNI,获利共计超过 20,000,000 美元。

    在此次攻击之后攻击者通过首先通过 Uniswap 和 WETH 将攻击获得的其他 token 全部换成 ETH,然后通过多次使用 Tornado.Cash 将 ETH 洗白。

    jinse.cn 2
    好文章,需要你的鼓励
    jinse.cn 2
    好文章,需要你的鼓励
    参与评论
    0/140
    提交评论
    文章作者: / 责任编辑:

    声明:本文由入驻金色财经的作者撰写,观点仅代表作者本人,绝不代表金色财经赞同其观点或证实其描述。

    提示:投资有风险,入市须谨慎。本资讯不作为投资理财建议。

    金色财经 > BlockSec > Popsicle Finance 双花攻击分析
    • 寻求报道
    • 金色财经中国版App下载
      金色财经APP
      iOS & Android
    • 加入社群
      Telegram
    • 意见反馈
    • 返回顶部
    • 返回底部