Velocore 的事件分析

本文为机器翻译
展示原文

2024 年 6 月 2 日,Velocore 的 CPMM 池遭受攻击,造成约 680 万美元的财务损失。此次攻击的根本原因是ConstantProductPool中计算交易费的逻辑错误,以及整数下溢。

概述

漏洞分析

在技​​术文档中,Velocore 建议用户直接与Vault 合约交互来执行操作。从用户的角度来看,最重要的函数是Vault.execute() 。此功能允许用户交换、质押、转换或投票,而无需知道内部池、路由器ETC的地址。此外,它支持批处理操作,允许用户在单个交易中执行多个操作。

感谢阅读 Verichains!免费订阅以接收新帖子并支持我的工作。

代币交换操作的典型执行流程如下:

  1. 用户使用tokenRef数组和操作列表( ops )调用SwapFacet.execute()

  2. 然后, SwapFacet调用其内部的_execute()函数来处理用户的操作。

    1. _execute()遍历ops并根据其类型处理每个操作。

    2. 如果当前操作是交换请求, _execute()会调用相应池的velocore__execute()来模拟交换并返回余额增量。然后它调用_verifyAndApplyDelta()来验证和应用结果。

  3. 返回外部execute()函数后,它会检查用户的余额并处理向用户钱包的转账或从用户钱包的提款。

Velocore 中有两种类型的池:易变池(CPMM)和稳定池(Wombat 池)。被攻击的池是一个易变池,因此我们回顾了ConstantProductPool.sol中的实现。

ConstantProductPool中的velocore__execute()函数负责计算交换结果,每当用户在 Velocore 上发起交换时, SwapFacet合约都会调用该函数。然而,这个函数有几个缺陷:

  1. 缺少调用者验证velocore__execute()应仅从 Vault 合约(例如本例中的SwapFacet )调用,但缺少此验证。这允许任何人调用该函数,从而引入潜在的攻击媒介。

  2. feeMultiplier无上限feeMultiplier无上限检查。逻辑表明, feeMultiplier每次调用velocore__execute()时都会增加,并且只有在The Block时间戳发生变化时(第三个代码块)才会重置为1e9 。由于feeMultiplier用于计算交易费用(第一个代码块中的effectiveFee1e9 ),因此当feeMultiplier超过 3.33e11 时, effectiveFee1e9将至少为3.33e11 * 3e6 / 1e9 = 1e9 ,这意味着费用超过 100% 。这会严重影响unaccountedFeeAsGrowth1e18 ,从而导致requestedGrowth1e18发生变化,最终影响池的余额。

  3. 未经检查的算法unaccountedFeeAsGrowth1e18的计算被放置在未经检查的块(第二个代码块)内。结合第二个缺陷,表达式1e18 - ((1e18 - k) * effectiveFee1e9) / 1e9可能会下溢,从而导致意外行为。

通过以上信息,我们现在可以了解黑客的策略:

  1. 操纵feeMultiplier :黑客直接多次调用velocore__execute()来人为提高feeMultiplier ,导致effectiveFee1e9超过 100%。这是在以下步骤中执行整数溢出攻击所必需的。在实际攻击中, velocore__execute()被调用了三次,参数相同。通过测试,我们通过仅调用velocore__execute()一次并使用略有不同的参数实现了相同的效果。重要的是要注意,这不会立即影响池余额,因为velocore__execute()不执行任何转移;它只更新feeMultiplier

  2. 耗尽USDC流动性:黑客利用闪电贷功能,试图使用 LP 代币从池中提取几乎所有USDC ,造成USDC稀缺,并显著影响兑换价格。在实际攻击中,黑客执行了三次操作,每次耗尽了池中 98% 的USDC 。在我们的测试中,我们发现我们可以在一次操作中实现相同的结果,结果没有差异。

  3. 利用整数下溢:最后,黑客进行了另一次单代币提取,选择了触发整数下溢的精确数量的USDC ,导致rpow()返回异常大的值。这导致矿池计算错误,向黑客奖励 LP 代币,而不是执行正确的提取。这使得黑客拥有足够的 LP 代币来偿还他们在前面步骤中借入的金额。

结论

尽管ConstantProductPool SwapFacet逻辑来更新池的余额并执行代币转移。但是, ConstantProductPool使用其自己的内部变量(独立于SwapFacet )计算增量并仅返回结果。这种设计造成了合约之间的脱节,导致沟通不畅,并最终导致漏洞利用。为了减轻未来的风险,我们建议 Velocore 重构其代码库,以在内部组件之间建立清晰而强大的逻辑。

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