KyberSwap 黑客攻击快速分析

本文为机器翻译
展示原文

根据审计公司Certik的分析,黑客通过利用 KyberSwap 部分借贷池哪怕是最小的漏洞,成功挖矿交叉互换手段窃取了借贷池。

11 月 22 日, KyberNetwork多个链遭受闪贷攻击,造成约 4700 万美元的损失。根据 Certik 的说法,使用这种技术,了解中心化流动性生成器的工作原理非常重要。

自动LP本质上是在所有交易发生的地方部署标准恒定乘积曲线 (x*y=k)。

Certik 发现,如果制作的资金池具有更严格的价格曲线上限,则可以更好地利用流动性。在狭窄的价格区间内拥有大量流动性支持也可以有效下降价格滑落的风险,因为交易规模必须与借贷池比例上涨才能产生相同的价格影响。

中心化流动性提供者模型由Uniswap v3 普及,允许LP(LP) 为其首选价格区间添加流动性。

Certik 指出,这种设计的结果是,每个流动性供应头寸 (LP) 必须单独跟踪,因为池中的流动性变得不匹配。价格范围可以分为Chia的“报价点”,允许有限合伙人在任意两个“报价点”之间提供流动性。价格变动指数(表示为 i)定义为相应价格的对数

流动性提供者的净流动性等参数存储在链表数据结构中。

实际上,这些头寸中的每一个都制作了用户定义的价格曲线。通过将所有不同的头寸聚合到一条价格曲线中,它允许单个池支持流动性提供者(LP)偏好的多样性。

当在某个价格变动范围内添加或减少流动性时,借贷池必须记录在这些价格变动范围超越时添加或释放的虚拟流动性数量,以及在该保证金范围内使用了多少筹码来触发流动性。代币置换筹码1 会导致当前池价格和当前“报价”向下移动,而代币置换筹码0 会导致当前池价格和当前“报价”上涨。执行交换时,当“tick”超越此边际左右移动时,流动性总量会增加或减少,这就是发生攻击的 KyberSwap 中的漏洞。

漏洞

简而言之,该漏洞存在于 KyberSwap Elastic 的computeSwapStep()实现中。该函数负责计算需要相减或相加的交易实际输入输出金额、需要收取的掉期费用,以及得到的平方根值作为sqrtP函数。

该函数最初被称为calcReachAmount()函数,并认为黑客的交易不会超越刻度保证金,但由于制作了一个大于targetSqrtP 的虚拟价格(通过调用函数“calcFinalPrice”计算),因此出现了错误因此,流动性不会被消除并导致下一次攻击。

攻击流程

此示例基于以太坊交易,其 txhash 为: 0x396a83df7361519416a6dc960d394e689dd0f158095cbc6a6c387640716f5475

该交易代表了六次攻击,均使用相同的方法。因此,Certik 以针对 USDC-ETHX 货币对的攻击为例。

1.首先,黑客从Uniswap闪贷 500 ETHx,并通过交换过量的 ETHx 来操纵只有 2.8 ETHx 的 KS2-RT 池((KyberSwap v2 Reinvestment 筹码)。黑客将 246,754 ETHx 兑换成 32389.63 USDC,耗尽了资金池流动性并将currentTick上涨至 305,000。

交换后,池中还剩下 249.5 ETHX 和 13.2 USDC。

可以看到,黑客最初想用 500 ETHX 兑换 USDC,但 246,754 ETHx 足以获得 32,389.63 USDC,并将currentTick上涨305,000。这意味着当时没有超过 305,000 点保证金的流动性可供黑客进行交换,因此被认为是真空。

2. 然后,黑客从 KyberSwap: Elastic Anti-Snippingposition Manager合约中调用mint()函数,以制作一个包含 16 USDC 和 5.87e-3 ETHX 的新借贷池。 “蜱”被放置在 305,000 到 305,408 的狭窄范围内,这意味着黑客创建了自己的借贷池来跟踪 305,000 的“蜱”。

随后,黑客删除了部分流动性,但在 305,000 至 305,408 的刻度范围内留下了一些流动性。

3. 黑客进行第二次从 ETHX 到 USDC 的兑换。他们以 305,000 的价格变动保证金兑换了 244.08 ETHX,获得了 13.6 USDC,并将价格变动保证金上涨至 305,408。

从表面上看,这似乎是一次奇怪的交换,因为黑客是唯一提供 305,000 到 305,408 之间流动性的人,但这是下一步的前提。

4. KyberSwap 使用compute SwapStep()函数来确定交易是否超过了tick间隔。部分功能如下图所示:

这里,重点关注calcReachAmount()函数。如果currentSqrtP (当前平方根价格)达到targetSqrtP ,此函数计算交易所需的筹码数量。

Cerik表示,在这笔交易中, usedAmount的值为244080034447360000000,而黑客输入兑换的ETHx数量为244080034447359999999,比usedAmount的值少了1。 computeSwapStep()函数确定此交易不足以耗尽当前报价范围内的流动性,不需要更改为另一个报价范围。意味着nextSqrtP不会更新为targetSqrtP

然后调用calcFinalPrice函数来计算下一个nextSqrtP值。这里重要的部分是,在计算过程中,掉期费用被计入流动性中。导致nextSqrtP的最终价格实际上高于最初预期,特别是高于“tick”范围内的价格305,408。

回到上面的交换函数,Certik 说通过比较sqrtPnextSqrtP的值来确定刻度幅度是否需要交换。这里的条件仅确定sqrtP是否等于nextSqrtP ,并且只有在等于时,才会调用下层函数updateLiquidityAndCrossTick()来增加或减少流动性( swapData.baseL )并超越保证金“tick”。

此时, sqrtP现在大于nextSqrtP 。这意味着黑客制作了一种当前价格已经超越了tick范围上限的其中,但却没有触发updateLiquidityAndCrossTick()函数来减少流动性,从而导致仿盘流动性的存在。

5. 最后,黑客进行了反向交易,将 USDC 换成 ETHx,将价格下降到略高于“tick”范围 305,408——黑客提供的流动性范围上限(从 305,000 到 305,408),略低于价格在“tick”范围内 304,982。

当价格从略高于 305,408 的价格进入 305,000 – 305,408 的“tick”范围(黑客提供流动性的范围)时,就会调用updateLiquidityAndCrossTick()函数。仿盘流动性被添加到305,000 – 305,408“tick”范围内的流动性中,与实际流动性相比,上涨了“tick”范围内值之间的流动性。随后,黑客在此价格范围内将 493,638 个 ETHx 兑换为 27,517 USDC(包括未包含在 305,000 – 305,408 报价范围内的约 250 个 ETHx)。 Certik 总结道,结果是,之前的成本得到了恢复,同时借贷池失去了所有 USDC。

6、闪电贷,完成攻击。

对跨多个区块链的KyberSwap 协议上的多个交易对对重复此过程,导致以下损失。

保利:1,180,097 美元;以太:7,486,868 美元; OP:15,504,542 美元;基础:318,413 美元; ARB:16,833,861美元; AVAX:23,526 美元。

Certik确认的攻击来自三个不同的以太坊地址(EOA),其中地址0x502占大部分资产。最初,地址0x502联系了项目方,告知他们休息一段时间后进行谈判。 KyberSwap团队随后提出了 10% 的奖励,截止日期为 UTC 时间 11 月 25 日早上 6 点。

相关赛道:
来源
免责声明:以上内容仅为作者观点,不代表Followin的任何立场,不构成与Followin相关的任何投资建议。
喜欢
1
收藏
评论