揭密1300万美元的Abracadabra GMX V2漏洞

本文详细分析了Abracadabra平台的GMX V2 CauldronV4漏洞,攻击者利用内部分数值未正确更新的设计缺陷,导致平台损失超过1300万美元。通过复杂的交易结构,攻击者能够在未实际提供足够抵押的情况下提取资金。文章探讨了这次攻击的机制、影响及预防建议。

"釜底抽薪:深入 $1300万 Abracadabra GMX V2 漏洞" 横幅

MIM Spell 简介 (Abracadabra.money)

Abracadabra.money 是一个平台,允许用户 存入带息代币 (ibTKNs) 作为抵押来借贷 Magic Internet Money (MIM),这是一种与美元Hook的稳定币。通过允许这些 ibTKNs(例如 yVault 代币)作为抵押,用户可以 解锁先前存入产生收益的头寸中的额外资本

在其底层,Abracadabra 是由模块化智能合约和 BentoBox 技术构成的。这种架构提供了基本功能,比如 非托管的保管(通过 DegenBox)、隔离的借贷市场(Cauldrons - 直意为“锅”)和 收益策略,可以对存储的抵押品产生利息。当用户在特定Cauldrons中存入抵押品时,他们可以基于此借贷 MIM。如果他们的抵押品价值低于某个阈值,清算人可以偿还用户的债务以换取夺取抵押品。

架构概述

  1. DegenBox (BentoBox 变种)
    • 核心保管,用于保管用户资金并将其转换为“股份”。
    • 这些股份可以通过部署的策略(例如,耕作收益)赚取利息。
    • Abracadabra 在 DegenBox 中存储 用户抵押品未借出的 MIM
  2. Cauldrons(隔离市场)
    • 每个Cauldrons是一个专门针对特定抵押品类型的“迷你 Kashi”市场。
    • 处理 借贷 MIM 的逻辑、跟踪 偿债能力 和执行 清算
    • 用户通过Cauldrons互动以存入抵押品和请求 MIM 贷款。
  3. 预言机
    • 每个Cauldrons必须实时了解其抵押品的 美元价值
    • 通常使用 Chainlink 或类似的外部预言机,或可以更新的“代理预言机”。
  4. 策略
    • 可选模块,连接到 DegenBox 以将闲置抵押品部署到收益农场。
    • 提高所有存款人在该代币的股份的总体价值。
  5. 外围合约
    • 兑换器(swappers):原子“操作”,交换代币以实现杠杆或偿还债务。
    • 包装器(wrappers):用于具有额外功能或奖励代币的特殊抵押品的适配器。
    • 提款器(Withdrawers):收集和分配协议费用。
    • CauldronOwner:一个主合约所有者,控制所有Cauldrons的参数。

这些合约共同允许 Abracadabra 创建多个隔离的借贷市场,每个市场具有自定义参数,同时确保 MIM 稳定币始终由抵押品 支持

GMX V2 CauldronV4 架构

为了支持 GMX V2(一个链上的永久性去中心化交易所),Abracadabra 引入了一个专门的 GmxV2 CauldronV4。GMX V2 具有 非原子的 存款和提款:用户下达订单,最终由保管人或外部回调来执行。以下是使 Abracadabra 能够处理这一异步流程的关键调整:

  1. OrderAgent & RouterOrder
    • 当用户想要将 GMX 头寸作为抵押(或提取它们)时,Cauldrons调用 OrderAgent
    • OrderAgent 部署一个与该用户专门绑定的 RouterOrder 代理。
    • RouterOrder 将存款/提款请求提交给 GMX。一旦请求完成,GMX 会回调到 afterDepositExecution()afterWithdrawalCancellation()
  2. Router 中的待处理抵押品
    • 通常,Cauldrons只使用链上的抵押品检查用户的偿债能力。
    • 对于 GMX V2,用户可能有一个“在途”的存款请求,还未被执行。
    • GmxV2 CauldronV4 扩展了 _isSolvent(),以计算用户在 RouterOrder 中的“待处理”抵押品。RouterOrder 合约中的 orderValueInCollateral() 函数返回用户在“运输中”实际上拥有多少代币。
  3. Cook 操作
    • Abracadabra 的 cook() 函数可以将存款抵押、借款 MIM、交换等操作捆绑在一起。
    • GmxV2 CauldronV4 添加了专业操作(ACTION_CREATE_ORDERACTION_WITHDRAW_FROM_ORDERACTION_CANCEL_ORDER)来管理 GMX 存款/提款订单。
    • 这种设计允许高级的单交易流(例如,“借款然后开一个 GMX 存款订单”)。
  4. 清算与 closeOrder
    • 在正常的Cauldrons中,如果用户的抵押品过低,协议会扣押链上的代币。
    • GmxV2 CauldronV4 还必须考虑任何 活动订单。如果用户破产,将 cancelOrder(),强行从 RouterOrder 提取 USDC 或 GMX 代币。
    • closeOrder() 函数将用户存储的 RouterOrder 地址设为零,最终化被强行关闭的位置。

流程示例:

  1. 存款:用户“创建一个订单”以在 GMX 中存入 USDC。存款最终产生 GM 代币,Router 将其作为抵押返回Cauldrons。
  2. 借款:如果用户在考虑链上的抵押品和待处理的 “orderValueInCollateral()” 后仍然“保持偿债能力”,则Cauldrons允许他们借款 MIM。
  3. 提款:用户可以通过另一个 GMX 订单类似地提款抵押品,一旦 GMX 处理,代币将被返回或取消。
  4. 清算:如果用户的实际抵押品降到阈值以下,Cauldrons将调用 liquidate(),可能会取消任何未完成的订单(归还剩余的 USDC)或扣押刚到账的 GM 代币。

在实践中,这种方法 桥接了 GMX V2 的异步设计 与 Abracadabra 的标准Cauldrons架构。然而,正如在漏洞中所见,如果系统 在部分清算或提款后仔细更新“待处理抵押品”,攻击者可能在纸面上看似偿债,而实际上却在耗尽协议。

审计范围

gmCauldronV2 合约于 2023年11月14日Guardian Audits 进行了审查(审计 PDF)。审计发现了大量问题,包括 4 个关键/高 严重性发现和 10 个中等 严重性发现——这表明代码库需要进一步完善。

重要的是,这是 在合约部署之前进行的唯一审计。虽然 Guardian 专业地完成了他们的审计范围,但在重大架构更改后没有进行 后续审计

发现如此多的漏洞,第二次审计不仅仅是建议 - 而是绝对必要的。

随后的漏洞并不是因为审计疏忽引起的,而是由于 协议团队未能在集成更改后寻求更深入的验证

攻击分析

背景:GmxV2 CauldronV4 的非原子存款

Abracadabra 的 GmxV2 CauldronV4 被设计用于处理 GMX V2 的非原子存款模型,用户创建的存款订单会在稍后执行。当存款成功时,GM 代币被记入用户的抵押品。然而,当存款失败时——例如,由于无法达到 minOut——GMX 合约会 返回原始代币(例如 USDC)到 RouterOrder。在这种情况下,Cauldrons仍然将这些返回的代币视为有效抵押品。

攻击者利用此点,故意强制存款失败,在 RouterOrder 合约中创建“幽灵抵押品”。orderValueInCollateral() 函数继续报告失败存款的全额价值,而Cauldrons在提取真实资金后并未将订单标记为已关闭。

准备和攻击时间线

以下顺序概述了攻击者在执行攻击之前的设置。

准备阶段

  • 钱包 1 收到 Tornado Cash 的 1 ETH。
  • 钱包 6 通过 Tornado Cash 收到 10 ETH(10 × 1 ETH)。
  • 钱包 6 通过 Stargate 将 ETH 桥接到 Arbitrum。
  • 钱包 1 通过 GMX 获取 3.31700399 gmETH/ETH 代币。
  • 钱包 1 设置批准并与 gmETH/ETH Cauldrons进行交互。
  • 钱包 1 分发 0.5 gmETH/ETH 代币给 钱包 2, 3, 4 和 5
  • 钱包 1 还向上述每个钱包发送 0.1 ETH。
  • 钱包 2-5 批准主合约并存入 gmETH/ETH。

攻击阶段

  • 钱包 1 部署漏洞合约:0xf29120acd274a0c60a181a37b1ae9119fe0f1c9c
  • 钱包 6 为漏洞合约提供 9.93 ETH 资金。
  • 攻击者发起了一系列跨多个钱包和Cauldrons的 cook() 交易。
  • 每个 cook() 包括故意失败的 GMX 存款,随后是清算和重新借款的序列。

到活动结束时,攻击者在大约100分钟内通过56笔交易抽走了 约1340万美元

完整活动日志 可通过官方的 事后分析 Google 表格 查阅。

市场影响

  • GMX 价格:从 $55.20 降至 $46.92下降 15.0%
  • MIM Spell 价格:从 $1.20 降至 $1.08下降 10.0%
  • 范围:只有“gmCauldron”集成受到影响;其他 Abracadabra Cauldrons保持不变。

漏洞利用

从根本上看,该漏洞源于 GmxV2CauldronV4 及其相关 GmxV2CauldronRouterOrder 合约中的 两个关键设计缺陷

  1. sendValueInCollateral() 函数在清算期间 从路由器移除真实代币,但并未更新内部状态变量,如 inputAmountminOutminOutLong。这一遗漏导致Cauldrons认为仍然存在相同数量的“潜在抵押品”,即使部分已被提取。
function sendValueInCollateral(address recipient, uint256 shareMarketToken) public onlyCauldron {
      (uint256 shortExchangeRate, uint256 marketExchangeRate) = getExchangeRates();

      uint256 amountShortToken = (degenBox.toAmount(IERC20(market), shareMarketToken, true) * oracleDecimalScale) /
          (shortExchangeRate * marketExchangeRate);

      shortToken.safeTransfer(address(degenBox), amountShortToken);
      degenBox.deposit(IERC20(shortToken), address(degenBox), recipient, amountShortToken, 0);
  }

orderValueInCollateral() 函数继续使用那些未更改的内部字段计算用户的待处理抵押品。由于这些值在部分清算或失败存款发生时从未减少,因此用户似乎持有比实际更多的抵押品——这使得欺诈性借贷成为可能。

function orderValueInCollateral() public view returns (uint256 result) {
      (uint256 shortExchangeRate, uint256 marketExchangeRate) = getExchangeRates();

      if (depositType) {
          uint256 marketTokenFromValue = (inputAmount * shortExchangeRate * marketExchangeRate) / oracleDecimalScale;
          result = minOut < marketTokenFromValue ? minOut : marketTokenFromValue;
      } else {
          uint256 marketTokenFromValue = ((minOut + minOutLong) * shortExchangeRate * marketExchangeRate) / oracleDecimalScale;
          result = inputAmount < marketTokenFromValue ? inputAmount : marketTokenFromValue;
      }
}

完整漏洞流程

设置阶段:存款失败与幽灵抵押品

攻击者在通过 GMX 存入抵押品时,以 不切实际的 minOut 值发起 cook() 调用。这导致 GMX 拒绝存款并将输入代币(例如,USDC)返回到 RouterOrder 合约。尽管收回了代币,但Cauldrons仍将该失败存款视为已成功,由于未更改的会计字段。

初始借款以资助抵押品

攻击者使用 cook() 借取少量 MIM,用于资助将在漏洞中循环使用的抵押品。

漏洞交易

确切的 cook() 步骤 第二个 cook() 调用包含多个操作:

  • 操作 5(借款):借款 MIM,将贷款价值比推高至清算阈值。
  • 操作 30(调用):调用攻击者的合约函数(get_before_liquidate_amount)计算在清算期间需要拉取多少抵押品以实现最大提取。
  • 操作 31(清算):自我清算该头寸。清算逻辑首先试图通过 BentoBox 抵押品覆盖债务,然后通过 sendValueInCollateral() 从攻击者的 RouterOrder 中提取额外代币。这些代币是来自于失败 GMX 存款返回的真实 USDC。
  • 操作 30(调用):调用攻击合约中的另一个函数(get_after_liquidate_amount)以计算现在可以借多少 MIM 基于未更改的幽灵抵押品。
  • 操作 5(借款):攻击者再次借款,这次是通过已经不存在但仍然由 orderValueInCollateral() 报告的抵押品支持。
    • 操作 30(调用):调用交换并提取所有从协议中借来的 MIM。

最终偿债能力检查(绕过)

cook() 批次结束时,Cauldrons调用 _isSolvent() 确保用户在所有操作后仍然保持偿债能力。然而:结果是,协议仍然根据过时的内部状态视用户为偿债能力,交易不会回滚。攻击者带着 借来的 MIM在清算期间被扣押的真实抵押品 走了,而仍然看似完全抵押。_isSolvent()cook() 批次结束时运行并错误通过,因为它使用了未更改的 orderValueInCollateral()

  • _isSolvent() 依赖于来自 RouterOrder 的 orderValueInCollateral()
  • 该函数继续根据 inputAmountminOutminOutLong 报告 原始、虚高的抵押价值
  • 即使在成功清算后,这些字段也从未更新。

因此,协议仍然根据过时的内部状态视用户为偿债能力,交易不会回滚

攻击者带着 借来的 MIM在清算期间被扣押的真实抵押品 走了,而仍然看似完全抵押。

_isSolvent()cook() 批次结束时运行并错误通过,因为它使用了未更改的 orderValueInCollateral()

重复并抽干 攻击者可以在不同的Cauldrons和钱包中重复此模式,每次都在基于无效内部会计通过偿债检查时抽走真实资产。

最大的攻击交易(≈932 ETH)

攻击者通过在一次大 cook() 调用中重复执行漏洞步骤,净赚了约932 ETH。

如何防止此攻击

以下是一个 diff,说明如何修补 sendValueInCollateral() 以减少用户的“纸”抵押字段。

注意:此代码片段仅为说明。在实际生产场景中,正确修复漏洞需要 对 RouterOrder 的内部会计逻辑有深入的了解,包括 inputAmountminOutminOutLong 如何在所有流程(例如存款、清算和取消)中使用。全面的修复还需要更新 orderValueInCollateral() 并正确跟踪关闭或消耗的订单。

function sendValueInCollateral(address recipient, uint256 shareMarketToken) external onlyCauldron {
   (uint256 shortExchangeRate, uint256 marketExchangeRate) = getExchangeRates();

   uint256 amountShortToken =
       (degenBox.toAmount(IERC20(market), shareMarketToken, true) * oracleDecimalScale)
       / (shortExchangeRate * marketExchangeRate);

    // 示例方法:减少 "inputAmount" 或 "minOut"
    // 以使 orderValueInCollateral() 不会继续高估用户的抵押品
    if (depositType) {
         inputAmount = (inputAmount >= someEquivalentShort) ? (inputAmount - someEquivalentShort) : 0;
         if (minOut > someEquivalentShort) minOut -= someEquivalentShort;
+     } else {
+     // 类似逻辑调整 (minOut + minOutLong) 或 inputAmount
+     }

   shortToken.safeTransfer(address(degenBox), amountShortToken);
   degenBox.deposit(IERC20(shortToken), address(degenBox), recipient, amountShortToken, 0);
}

额外的最佳实践

  1. 中间偿债能力检查:如果协议的 cook() 函数在“批量”执行多个操作,可以在每个主要步骤后,而不仅仅是在最后调用 _isSolvent()
  2. 严格审计:引入非原子订单系统(带有“纸”抵押品)应该触发更深入的会计检查。
  3. 限制自我清算:一些协议禁止在单个交易中进行部分或自我清算,除非经过彻底验证。

后果

  • $1340 万的低抵押 MIM:通过56笔漏洞交易在 五个 GM Cauldrons 中铸造了约 1340 万 MIM
  • 持续时间:此次攻击持续了约 1 小时 40 分钟,从 07:57:52 AM UTC 开始,到 09:37:36 AM UTC 结束。
  • 市场影响
    • GMX:价格从 $55.20 降至 $46.92(−15.0%)
    • MIM Spell:价格从 $1.20 降至 $1.08(−10.0%)
  • 操作中断:在 09:46:22 AM UTC,为了控制进一步损害,所有 GM Cauldrons的借贷被暂停。

协议的应对措施

发现漏洞后,Abracadabra 实施了紧急对策并启动恢复工作:

  • 禁用借贷:在漏洞之后立即暂停所有 gmCauldron,以防止进一步损害。
  • OrderAgent 失效:将 orderAgent 地址设置为 0x000…000,以防止继续创建 GMX 存款。
  • 成功恢复被困资金:成功回收了大约 $260,000 值的资产,这些资产在漏洞后仍滞留在 RouterOrder 合约中。
  • 与 Hexagate 实时监控
    • 集成 Hexagate 监控Cauldrons,但持有被攻陷资产的 DegenBox 并未被监控。
    • 事后看来,包括 DegenBox 将使得更早的检测和自动响应成为可能。
  • 多方协作:安全研究人员、Guardian Audits、Chainalysis 和 Seal 911 社区协助追踪资金和进行法证分析。
  • 沟通与悬赏
    • 悬赏 20%:宣布对安全归还被盗资金的 20% 悬赏(~$2.58M)
    • DAO 宣布正在 等待攻击者的沟通,通过链上消息及 reward@abracadabra.money

注意:这并不是 Abracadabra 架构第一次被利用。在 2024年2月,其 CauldronV4 债务会计机制 的早期漏洞被利用提取了超过 $640 万

我们的 Three Sigma 团队发布了对此事件的详细分析,涵盖了如何通过股份通货膨胀操纵内部借贷逻辑。

阅读更多 Abracadabra Money 漏洞分析 - 2024年2月

合约地址

受影响的合约

🧑‍💻攻击者钱包

常见问题解答 (FAQ)

1. 什么是 Abracadabra GMX 漏洞?

Abracadabra GMX 漏洞指的是对协议的 GmxV2 CauldronV4 的 1300 万美元攻击,其中攻击者操纵内部会计逻辑,使其在自我清算中看似偿还,同时提取真实抵押品。

2. Abracadabra 漏洞损失了多少?

大约损失了价值约 1300 万美元的加密资产(≈6262 ETH)通过一系列精心构建的 cook() 交易被从协议中盗取。

3. 在 Abracadabra 黑客攻击中有涉及预言机操纵吗?

没有。该漏洞并未涉及预言机操纵。偿债能力计算中使用的价格是准确的;问题在于 RouterOrder 合约中的过时抵押会计。

4. 什么是 GmxV2 CauldronV4?

GmxV2 CauldronV4 是 Abracadabra 上的专用借贷市场合约,支持 GMX V2 的异步存款和提款系统,允许用户根据 GMX LP 头寸借贷 MIM。

5. 攻击者如何绕过偿债能力检查?

攻击者利用 orderValueInCollateral() 在部分清算后从未更新的事实。他们借取 MIM,自我清算,提取真实资金,且在 cook() 调用结束时仍然通过了 _isSolvent()

6. Abracadabra 合约中的 cook() 函数是什么?

cook() 是一个批处理函数,允许用户在一笔交易中执行多个操作(例如,存款、借款、提款、清算)。偿债能力只在最后进行检查,这在攻击中发挥了关键作用。

7. 什么导致了虚高的抵押值?

sendValueInCollateral() 函数从 RouterOrder 中移除了真实代币,但未减少 inputAmountminOut 等内部值。这导致 orderValueInCollateral() 返回虚高的数字。

8. Abracadabra 对攻击做出了什么反应?

Abracadabra 停止了受影响市场的借贷,与 Chainalysis 和其他合作伙伴协作追踪资金,并为安全归还被盗资产提供了 20% 的悬赏(约 258 万美元)。

9. DeFi 协议可以从这一漏洞中学到什么?

DeFi 协议应该严格测试涉及异步资产流的边缘情况,确保内部会计与实际代币流动相符,并在偿债能力检查时避免仅依赖乐观的“纸抵押品”。

  • 原文链接: threesigma.xyz/blog/abra...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Three Sigma
Three Sigma
Three Sigma is a blockchain engineering and auditing firm focused on improving Web3 by working closely with projects in the space.