欢迎访问本站!

首页科技正文

Popsicle Finance 双花攻击剖析

admin2021-08-0647

手机新2管理端

www.9cx.net)实时更新发布最新最快最有效的手机新2管理端网址,包括新2手机网址,新2备用网址,皇冠最新网址,新2足球网址,新2网址大全。

,

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

代码剖析

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

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

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

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

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

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

最后,会将纪录在 userInfo 中的 Rewards 状态举行更新。看到这里,机枪池的代码实现照样对照相符逻辑的。然则在函数开头我们发现了 updateVault modifier,这个函数会在 collectFees 的函数体之前运行,破绽也许在 updateVault 相关的函数中。

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

以上是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 中记账的存款奖励。

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

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

我们设想一个攻击流程:

USDT场外交易平台

U交所(www.usdt8.vip),全球頂尖的USDT場外擔保交易平臺。

  • 攻击者向机枪池中存入一定的流动性,获得一部门 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 洗钱。

本次攻击生意主要由数个 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/)给出的生意挪用图如下,其中部门主要生意用红字举行标注:

利润剖析

本次攻击一共赚钱:2.56k WETH,96.2 WBTC,160k DAI,5.39m USDC,4.98m USDT,10.5k UNI,赚钱共计跨越 20,000,000 美元。

网友评论