来源:Beosin
北京时间2024年3月5日深夜,据Beosin Trace平台显示,Arbitrum链上的WooPPV2合约项目受到价格操控攻击,造成约850万美元的损失。黑客利用闪电贷借出USDC.e和Woo代币,然后通过WooPPV2合约进行频繁的代币兑换。由于WooPPV2合约的价格计算存在缺陷,黑客能够操控兑换过程中的价格,导致大量Woo代币被盗。Beosin安全团队第一时间对本次事件进行了分析。
漏洞分析
WooPPV2合约中存在一个swap函数,用户可以调用该函数进行代币兑换,这里主要是USDC.e和Woo两者的兑换(下文均按USDC.e与Woo之间的兑换来分析),其中函数中的quoteToken变量表示的就是USDC.e。
_sellQuote函数和_sellBase函数逻辑差不多,都是根据价格计算兑换的代币数量,再将代币发送给调用者。_sellQuote是当调用者用USDC.e来兑换Woo代币时调用的函数,其中主要的函数是state以及_calcBaseAmountSellQuote,state是用于返回保存Woo价格的结构体,_calcBaseAmountSellQuote是用户计算兑换数量以及新价格的函数。
接下来我们看_calcBaseAmountSellQuote函数实现逻辑,baseAmount为计算出来的兑换数量,其中主要逻辑是USDC.e数量除以Woo的价格,得到能兑换出的Woo的数量,接下来根据当前价格以及兑换数量计算出兑换之后的新价格。
_sellBase函数与_sellQuote函数相同,只是_calcQuoteAmountSellBase函数有些许不同,主要逻辑是Woo数量乘以Woo的价格,得到能兑换出的USDC.e的数量。
根据兑换逻辑我们能发现一个问题,这种兑换数量的计算逻辑与Uniswap等传统swap的乘积恒定模型不同,这种模式是直接根据价格做乘除来计算数量,使得兑换过程不存在滑点,但价格又会随着兑换而变化。如果调用者精心计算,就能将里面的代币套取出来。
举个例子:
如果池子里面初始存在1000个A代币和1000个B代币,B代币价格为1。那么如果使用500个A代币,便能兑换出500个B代币,此时池子变为1500:500,B代币价格将上涨,例如变为2。接下来,使用兑换出的500个B代币,将兑换出1000个A代币,最终池子变为500:1000,凭空套出500A代币。
此次事件,攻击者便是使用了该安全问题,我们来看看攻击者是如何进行攻击的。
攻击流程
本次事件攻击者通过多次相同的手法进行攻击,这里以
0xe80a16678b5008d5be1484ec6e9e77dc6307632030553405863ffb38c1f94266这笔交易为例。
1.攻击者通过闪电贷借出1000多万枚USDC.e以及272万枚Woo代币。
2.接下来,攻击者分三次使用10万枚USDC.e兑换Woo代币,此时可以看到Woo价格还处于正常价格,攻击者目前持有800多万枚Woo。
3.紧接着,攻击者直接使用800多万枚Woo代币去兑换USDC.e,由于上述问题,此时800多万枚Woo是全部按照正常价格进行兑换的,兑换了200多万枚USDC.e,并且根据上述公式计算出此时Woo的价格为7,缩小了近1000万倍。
4.最后,由于Woo代币价格极小,导致攻击者使用极少的USDC.e就将800多万枚Woo代币兑换出来,最后归还闪电贷离场。
资金追踪
黑客攻击后,攻击者将200枚ETH通过跨链桥转至以太坊链上的地址上,其余2000多枚ETH保存在Arbitrum链的地址上,截止发稿时,资金均未移动。
鉴于此次在Arbitrum链上发生的价格操控攻击事件,我们必须认识到在虚拟资产领域中安全风险的重要性。