SpaceGodzilla价格操纵漏洞分析

简要

因为前面分析的 Daoswap EXP 的攻击者是SpaceGodzilla Exploiter,说明这个攻击者之前还攻击过SpaceGodzilla。通过调用栈分析,发现攻击合约的结构大致相似,趁此机会,就一并分析下漏洞原理。

SpaceGodzilla同时具有代币和AMM的功能,黑客利用了其中合约中没有使用过的函数,通过扰乱LP中的兑换比例,从而获取了暴利。

漏洞说明

SpaceGodzilla Source Code

合约分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function swapAndLiquifyStepv1() public {
// ETH 的 数量
uint256 ethBalance = ETH.balanceOf(address(this));
// Godzilla token的数量
uint256 tokenBalance = balanceOf(address(this));
addLiquidityUsdt(tokenBalance, ethBalance);
}

// swap之后添加流动性
function swapAndLiquify() public {
uint256 allAmount = balanceOf(address(this));
uint256 canswap = allAmount.div(6).mul(5);
uint256 otherAmount = allAmount.sub(canswap);
swapTokensForOther(canswap);
uint256 ethBalance = ETH.balanceOf(address(this));
if(ethBalance.mul(otherAmount) > 10**34){
addLiquidityUsdt(ethBalance, otherAmount);
}
}

在源代码中存在一个swapAndLiquifyStepv1(),直接向池子中添加流动性。合约中还存在一个正常的方法swapAndLiquify,所以看起来,swapAndLiquifyStepv1()用来向LP流动池中添加流动性,本只应该在向LP池转账时,应该设置成只能internal调用。但在实际代码中,却设置成了public属性,导致黑客swapAndLiquifyStepv1后,导致LP流动池中token数量混乱,产生了套利空间。

漏洞分析

既然知道了漏洞合约中存在问题的函数,下面以实际的攻击交易来进行说明。

0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca4

整个漏洞的攻击过程如下:

  1. 从大量不同的Pair中通过闪电贷和交换等获得了295.2万的USDT,此为初始的攻击资本
  2. 将295.2万的USDT,在GodzillaUSDT的流动池中换出73,775,430,786,944,730,258,898,675,433,018个Godzilla币
  3. 调用swapAndLiquifyStepv1漏洞函数,将LP流动池中的Godzilla与USDT的兑换比例完全打乱
  4. LP流动池中的比例已经打乱,此时用使用71,562,167,863,336,388,351,131,715,170,010个Godzilla币兑换出297.8万的USDT,净套利2.6万USDT

通过调用栈,对具体的调用过程进行详细分析。

第一步,通过从不同Pair中进行闪电贷

第二步,获得当前LP中两个Token的数量

  • Token0,SpaceGodzilla(0x2287C04a15bb11ad1358BA5702C1C95E2D13a5E0)中的数量是,76041697635825849047705725848735
  • Token1,BUSD(0x55d398326f99059fF775485246999027B3197955)中的数量是,90478604689102338898952

此时,SpaceGodzilla和BUSD之间的比例是 840438442.8464187:1

K = X*Y,当前的K是 6880146700280134903645644790330265837423480505602025720

第三步,计算当前攻击合约中的USDT的数量

当前攻击合约通过闪电贷的方式,最终获得了 2952797 BUSD

第四步,swap特定数量的SpaceGodzilla

通过调用栈分析,攻击合约通过LP兑换出73775430786944730258898675433018数量的SpaceGodzilla。

兑换出来的SpaceGodzilla,是经过特定计算的。

攻击合约的BUSD 2952797730003166405412733

  • Token0,数量是,76041697635825849047705725848735
  • Token1,数量是,90478604689102338898952

兑换前后,需要满足的公式是:XY=k,(X-DX)(Y+DY)=K

当前条件是:已知X,Y,DX,就可以计算出DY,即 73775430786944730258898675433018

所以兑换出来的 SpaceGodzilla 数量就是 73775430786944730258898675433018

第五步,调用swapAndLiquifyStepv1

调用swapAndLiquifyStepv1,将SpaceGodzilla合约中的SpaceGodzilla代币和BUSD全部放入到Pancake中提供流动性

第六步,重新计算当前LP中两个Token的数量

当攻击合约通过swapAndLiquifyStepv1之后,因为提供了流动性,所以LP中的两个代币的数量发生了改变。

  • Token0,SpaceGodzilla(0x2287C04a15bb11ad1358BA5702C1C95E2D13a5E0)中的数量是,2288901594081170758102038305061
  • Token1,BUSD(0x55d398326f99059fF775485246999027B3197955)中的数量是,3073671601005728817436539

此时,SpaceGodzilla和BUSD之间的比例是 744679.9434696357:1(相比之前的840438442.8464187:1变化巨大)

K = X*Y,当前的K是 7035331827224036947372569921877688319008790342490023879

相比没有提供流动性之前,K值变大了。

第七步,将攻击合约中的SpaceGodzilla全部转账到LP中

攻击合约将在第四步中兑换出来的73775430786944730258898675433018的SpaceGodzilla,全部转账到了LP中。可以看到实际的转账数量是71562167863336388351131715170010。数量变少了。这个是因为Godzilla _transfer过程中会收取3%的takeFee。具体代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
function _transfer(
address from,
address to,
uint256 amount
) internal override {
......
if (takeFee) {
super._transfer(from, address(this), amount.div(100).mul(3));
_takeInviterFeeKt(amount.div(100000));
amount = amount.div(100).mul(97);
}
super._transfer(from, to, amount);
}

两个数字之间的差额就是被Godzallia合约收走的takeFee,这个takeFee是在_transfer中被收取的。

第八步,通过LB兑换处USDT

最终兑换出来 2978176 BUSD,攻击者通过闪电贷贷出了2952797 BUSD,最终盈利是 25379 BUSD

兑换出来的 BUSD 也是特定计算的。

攻击合约的SpaceGodzilla 73775430786944730258898675433018

  • Token0,数量是,2288901594081170758102038305061
  • Token1,数量是,3073671601005728817436539

兑换前后,需要满足的公式是:XY=k,(X-DX)(Y+DY)=K

当前条件是:已知X,Y,DX,就可以计算出DY,根据公式X’Y’=K’ , (X’+ DX)(Y’-DY)=K’, 求DY

计算得到,DY 是 2952797730003166405412733

所以兑换出来的 BUSD 数量就是 2952797730003166405412733

漏洞复现

数学原理

有一个很关键的问题,是不需要重复攻击者的步骤,使用任意的BUSD进行攻击,都可以获得盈利呢?结果显然不是的,可以看到整个攻击过程还是涉及到对于AMM机制的理解和计算。整个攻击背后的数学原理如下:

降低分析复杂度,不考虑Dex的交易过程中的手续费磨损同时也要确保token再转账的过程中没有额外的手续费:

正如这篇文章中的最后的结论,因此,这套攻击手法还是要看LP的初始状态以及在攻击过程中的一些参数的配合,才能达到套利的目的,不然自己会被反撸。

总结

参考

https://learnblockchain.cn/article/4396

https://learnblockchain.cn/article/4395

https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/SpaceGodzilla.exp.sol

https://mp.weixin.qq.com/s/JF4bvVoHbOZkjbO2YwGiWw

文章作者: Oooverflow
文章链接: https://www.oooverflow.com/2022/10/17/SpaceGodzilla-vuln/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Oooverflow