Popsicle Finance漏洞分析


攻击信息:

攻击者地址:

0xf9E3D08196F76f5078882d98941b71C0884BEa52

攻击合约:

A:

0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6

B:

0x576Cf5f8BA98E1643A2c93103881D8356C3550cF

C:

0xd282f740Bb0FF5d9e0A861dF024fcBd3c0bD0dc8

攻击交易:0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc

流程分析:

首先看到攻击者,通过闪电贷借出大量的资金。

 然后通过添加流动性,获得PLP代币10.52个。

 在然后把PLP代币发送给攻击合约B,攻击合约B再发送给攻击合约C,最后再把PLP发送给合约A,来取消流动性。

 然后往下看,就看出问题了,为什么会向攻击合约B和攻击合约C转账了?

 代码分析:

从上面知道,攻击合约得到了PLP代币,然后发送给了合约B。这里我们知道问题出在转账上面。跟踪到这一处调用。

 从图中,可知调用了SorbettoFragola合约中的collectFees函数,这里直接debug,一步一步看。

第一步:

攻击合约B调用,SorbettoFragola合约中的collectFees函数,然后进入updateVault修饰器中的_updateFeesReward函数。account是攻击合约B。

 进入到_updateFeesReward函数,这里我们一步一步看。

 这里返回的零,没有什么异常,在往下面走。

 返回的的是"90984415496720749373",没有异常。

 

 进入_fee0Earned函数,我们看到output就有问题了,因为对应参数user.token0Rewards,为"957182808388617756829",在往下面跟。

 

 问题出来了,balanceOf获取的是用户的PLP余额,并带入计算。恰好是传入的10.52。最后调用collectFees函数退出流动性。

 1     function collectFees(uint256 amount0, uint256 amount1) external nonReentrant updateVault(msg.sender) {
 2         UserInfo storage user = userInfo[msg.sender];
 3 
 4         require(user.token0Rewards >= amount0, "A0R");
 5         require(user.token1Rewards >= amount1, "A1R");
 6 
 7         uint256 balance0 = _balance0();
 8         uint256 balance1 = _balance1();
 9 
10         if (balance0 >= amount0 && balance1 >= amount1) {
11 
12             if (amount0 > 0) pay(token0, address(this), msg.sender, amount0);
13             if (amount1 > 0) pay(token1, address(this), msg.sender, amount1);
14         }
15         else {
16             
17             uint128 liquidity = pool.liquidityForAmounts(amount0, amount1, tickLower, tickUpper);
18             (amount0, amount1) = pool.burnExactLiquidity(tickLower, tickUpper, liquidity, msg.sender);
19         }
20         user.token0Rewards = user.token0Rewards.sub(amount0);
21         user.token1Rewards = user.token1Rewards.sub(amount1);
22         emit RewardPaid(msg.sender, amount0, amount1);
23     }

攻击合约调用collectFees函数主要是利用函数中的修饰器触发_updateFeesReward

 在利用获取的balanceOf,去更新奖励。就相当于一个凭证,可以多次使用。