微小舍入损耗,巨额资金损失:对近期 Balancer 事件的深度分析

微小舍入损耗,巨额资金损失:对近期 Balancer 事件的深度分析

更新于2023年9月15日:Balancer 已发布了官方事后复盘,其中详细描述了此次事件的整个过程,包括经验和教训。这篇事后复盘的文章叙述细致且精彩,引人入胜,绝对值得您花时间阅读。

从安全角度来看,此次事后复盘揭示存在两个漏洞。第一个是我们报告中讨论过的向下取整错误,第二个是报告中所述在攻击步骤 3.6 和 3.7 中发生的“供应量为零时重置费率”问题。Balancer 的报告认为第二个是更关键的问题,而第一个是辅助因素。然而,我们认为两个漏洞对于盈利性利用都同样重要:

  1. 第一个漏洞被用来推高代币费率,是盈利的根本原因。没有它,盈利将不可行。

  2. 第二个漏洞通过平衡 bb-a-tokens 的债务使漏洞利用成为可能。如果没有它,由于 bb-a-tokens 流动性差,攻击将失败(除非攻击者以某种方式获得它们)。

2023 年 8 月 22 日,Balancer 公开宣布存在影响多个增强型资金池的关键漏洞,并敦促用户立即从受影响的资金池中提取 LP。Balancer 已启动紧急缓解程序以保护大部分 TVL,但仍有部分资金面临风险。不幸的是,在 8 月 27 日,即五天后,我们注意到已发生数起攻击。此后,超过 212 万美元的资产被盗。

在撰写本报告时(距离公告发布已超过三周,我们认为此时可以安全发布),Balancer 尚未发布对该漏洞的深入分析。在本报告中,我们旨在提供一个全面的分析,主要基于一次攻击交易

主要收获(TL;DR)

  • 我们的调查表明,根本原因源于***linear 资金池中向下取整逻辑导致的币价操纵。这进而错误地影响了相应 boosted 资金池使用的缓存代币费率***。
  • 此事件强调了及时通知从易受攻击来源分叉的项目的重要性,这对整个社区都构成了重大挑战。
  • 持续不断的攻击凸显了主动威胁防御的必要性,这可以有效地帮助减轻潜在损失。

在接下来的章节中,我们将首先提供关于 Balancer 的一些基本背景信息。之后,我们将对该漏洞及相关攻击进行全面分析。最后,我们将简要总结我们迄今为止观察到的攻击及其相应的利润。

0x1 Balancer 背景

Balancer V2 [1] 是一个去中心化的自动做市商 (AMM) 协议,代表着可编程流动性的灵活构建块。与其他 AMM 中代币核算与资金池逻辑相结合的方式不同,Balancer 将代币核算和管理与资金池逻辑分开,从而可以通过减少大量代币转移来提高交易效率。

Balancer 支持多种资金池。每个资金池都关联着一个名为 BPT (即 Balancer Pool Token) 的 LP 代币。基本上,BPT 的价值是根据所有底层代币的总价值计算的。

Balancer 支持多跳交易,也称为 batch swaps,它利用注册在 Vault 中的所有资金池的最佳价格。具体来说,Vault 提供 batchSwap 函数以促进多跳交易。

Balancer 资金池中的 flash swap 消除了对执行交易所需任何输入代币的持有需求。相反,在识别出不平衡后,您可以指示 Vault 执行交易,然后获得奖励。

0x1.1 Balancer 中的各种资金池

下面,我们简要介绍一些与此漏洞相关的资金池概念。

  • Linear Pools: Linear 资金池 [2] 是 Balancer 资金池,它们以已知的汇率促进资产与其包装的、产生收益的对应资产之间的兑换。顾名思义,Linear 资金池使用线性数学。一个 linear 资金池将持有三种代币,包括:

    • 两种资产,即具有相同底层代币价值的 main 代币和 wrapped 代币;
    • 相应的 BPT (Balancer Pool Token)。请注意,BPT 是 ERC-20 代币。
  • Nesting Linear Pools: Linear Pool 的 BPT 可以嵌套在另一个资金池中。这会在基础资产和外部资金池代币之间创建一个简单的 batchSwap 路径,因为交易者可以从 BPT 交易到 Linear Pool 的底层代币之一。

  • Composable Stable Pools: Composable Stable Pools [3] 是为预期以接近平价或已知汇率持续交易的资产设计的。Composable Stable Pools 使用稳定数学,允许大额交易在遇到显著价格影响之前发生,从而大大提高了同类和相关类交易的资本效率。

当一个资金池允许与其自身 LP 代币进行交易时,它就是可组合的。将其 LP 代币放入其他资金池(或“嵌套”)可以轻松地从嵌套资金池代币实现到外部资金池代币的 batchSwap

  • Boosted Pools: Boosted 资金池 [4] 旨在提高大型资金池闲置流动性的资本效率。Boosted 资金池实际上是其他资金池的一个子类。例如,一个 boosted 资金池可以构建在 linear 资金池之上。

Boosted Pools 的设计旨在通过允许用户为常用代币提供交易流动性,同时将闲置代币转发到外部协议,从而实现高资本效率。这使流动性提供者除了赚取交易费用外,还能获得 Aave 等协议的优势。

0x1.2 易受攻击的增强型资金池的具体示例:Balancer Boosted Aave USD

Balancer Boosted Aave USD(符号:bb-a-USD)是一个可组合稳定币资金池,可在三种稳定币(即 USDC、USDT 和 DAI)之间进行交易,同时将闲置流动性发送到 Aave。底层 linear 资金池是:

  • bb-a-USDC(包含 USDC 和已包装的 aUSDC)
  • bb-a-USDT(包含 USDT 和已包装的 aUSDT)
  • bb-a-DAI(包含 DAI 和已包装的 aDAI)

具体来说,bb-a-USD 是一个可组合稳定币资金池的集合,其中包含三个不同 linear 资金池的资金池代币,而每个 linear 资金池都有关联的稳定币:DAI、USDC 和 USDT。下图由官方文档 [5] 提供,展示了 bb-a-USD 的结构:

0x1.3 如何计算 BPT 的价格

一个自然出现的重要问题是,在兑换特定数量(即 amountIn)的 BPT 为另一代币的特定数量(即 amountOut)时,如何确定 BPT 的价格。

Balancer 在其采用的数学公式 [6, 7] 中提供了详细描述,具体取决于不同的资金池。为简洁起见,我们在此处进行抽象和总结最相关的概念。

linear 资金池为例,BPT 的价格是在 LinearPool 合约的 onSwap 函数中计算的。

计算可以总结如下:

amountOut=amountIntokenRateamountOut=amountIn*tokenRate

这里的 tokenRate 是根据以下公式计算的:

_INITIAL_BPT_SUPPLY\_INITIAL\_BPT\_SUPPLY 是一个常量值:211212^{112} - 1

在上述公式中,分子可以简化为 main 代币余额与 wrapped 代币余额之和,而分母是预定义值(即 _INITIAL_BPT_SUPPLY)与 BPT 余额之差。

值得注意的是,为了进行计算,所有涉及的代币余额都需要标准化,因为不同的代币可能有不同的精度。具体来说,给定代币的实际余额将乘以一个相应的放大因子,该因子由 _scalingFactors 函数确定。

(1) `Linear` 资金池的放大因子

BPTmain 代币都具有常规的、恒定的放大因子。

(2) 像 `bb-a-USD` 这样的 `Boosted` 资金池的放大因子

boosted 资金池的计算有点复杂。具体来说,返回的放大因子是原始放大因子(例如 1e18)与代币费率的乘积,该代币费率是从缓存的代币费率(如果存在)获得的。

缓存的代币费率从何而来?存在一个名为 _updateTokenRateCache 的私有函数。显然,该函数将首先通过调用该代币的 getRate 函数来检索费率,然后进行缓存。

再次以 bb-a-USDC 为例,相应的 getRate 函数的核心逻辑遵循我们之前讨论的公式。

请注意,有三种可能的路径可以触发 _updateTokenRateCache 函数:

此外,对于通过 onSwap 函数的路径,在进行更新时会进行过期检查:

0x2 漏洞分析

根本原因在于***linear 资金池的 onSwap 函数中的向下取整逻辑导致的币价操纵。这进而错误地影响了 boosted 资金池使用的缓存代币费率***。

具体来说,当调用 _downscaleDown 函数时,amountOut 会被向下取整。因此,如果 amountOutscalingFactors[indexOut] 之间存在显著的数量差异,_downscaleDown 函数的返回值可能会为零。

例如,如果我们使用 bb-a-USDC(作为 BPT)在 bb-a-USDC 资金池中交易 USDC(作为 main 代币),当 amountOut 小于 1,000,000,000,000 时,返回值总是会被向下取整为零。这将增加 bb-a-USDC 的余额,因为它会被视为单向增加 bb-a-USDC 的流动性。

因此,如果 BPT 是用于交易的代币,则其费率将上升,这与计算费率的公式相符,因为分子保持不变而分母减小。此漏洞可能被利用,导致(巨大的)价格差异。

0x3 攻击分析

攻击交易包含以下攻击步骤:

  1. 通过 Aave 的 Flashloan 借入 300,000 USDC。
  2. 在 bb-a-USDC 资金池中,将 1.067753 USDC 兑换为 0.970495 aUSDC。
  3. bb-a-USDCbb-a-USD 资金池中执行 batchSwap,即以 42,203 USDC 获得 15,628 bb-a-USDC、139,431 bb-a-DAI 和 248,868 bb-a-USDT。详细步骤总结如下表(包含精度):
  1. 将 LP 代币兑换为相应的底层稳定币:
  • bb-a-DAI 资金池中,139,431 bb-a-DAI -> 141,127 DAI
  • bb-a-USDC 资金池中,15,628 bb-a-USDC -> 15,685 USDC
  • bb-a-USDT 资金池中,248,868 bb-a-USDT -> 253,461 USDT
  1. 偿还闪电贷,最终利润为:
  • 114,324 DAI
  • 253,461 USDT
  • 0.970495 aUSDC

值得注意的是,攻击者在步骤 2 中从 bb-a-USDC 资金池中耗尽了 aUSDCUSDC,这使得步骤 3 中的币价操纵更容易,即攻击者只需专注于 USDCbb-a-USDC

这里的步骤 3 起着关键作用。现在让我们深入研究此步骤的细节,以找出攻击者为何能够盈利。具体来说:

  • 步骤 3.1 用于从 bb-a-USDC 资金池中提取 USDC 并交换 bb-a-USDC
  • 步骤 3.3 和 3.4 用于将 bb-a-USDC 兑换为 bb-a-DAI,而步骤 3.5 用于将 bb-a-USDC 兑换为 bb-a-USDT
  • 步骤 3.7 用于在 bb-a-USDC 资金池中用 USDC 兑换 bb-a-USDC

这里的步骤 3.2 和 3.6 由于上述向下取整问题,没有交换任何目标代币(即 USDC),因此交易后目标代币的余额保持不变,这可以被视为向 bb-a-USDC 资金池增加了额外的 bb-a-USDC 流动性。

显然,异常交易主要发生在步骤 3.4、3.5 和 3.7。接下来,我们将逐一详细分析这些步骤。

(1) bb-a-USDC -> bb-a-DAI

在步骤 3.3 中,bb-a-USDCbb-a-DAI 之间的汇率几乎为 1,而在步骤 3.4 中,汇率变为 19

  • 步骤 3.3:1,000,339,378,515,783,699 / 1,000,000,000,000,000,000 = 1.00
  • 步骤 3.4:139,430,482,942,020,211,267,110 / 7,300,000,000,000,000,000,000 = 19.10

回顾我们之前讨论的代码逻辑,在步骤 3.3 中,在返回之前缓存的代币费率以计算放大因子(1,012,181,365,780,643,700)后,它会将费率更新为计算一个新值(40,240,000,000,000,000,000)。这个更新后的值随后在步骤 3.4 中用作新的放大因子。由于原始放大因子保持不变(即 1e18),这意味着新费率比旧费率高约 40 倍。

但是,这个显著的增长来自哪里?让我们回顾一下计算 tokenRate 的公式。由于在步骤 2 中耗尽了 aUSDC 的余额,tokenRate 的计算可以简化为:

这里的 nominalMainBalance 的实际值是由于步骤 3.2 中发生的向下取整。

(2) bb-a-USDC -> bb-a-USDT

步骤 3.5 使用相同的技巧来获得更多的 bb-a-USDTbb-a-USDCbb-a-USDT 之间的汇率超过 12

  • 248,868,905,733,352,246,491,156 / 20,000,000,000,000,000,000,000 = 12.44

(3) USDC -> bb-a-USDC

此外,bptBalance 在步骤 3.6 中增加,然后在步骤 3.7 中 bptSupply 变为零。通过这样做,有可能以接近 1:1 的汇率将 USDC 兑换为 bb-a-USDC

0x4 攻击与利润总结

截至目前,我们已经观察到数十起攻击,造成超过212 万美元的损失。总而言之,这些攻击是由三个不同的账户执行的,如下所示:

Balancer 由于此漏洞总计损失了约 100 万美元。在 Balancer 首次遭受攻击不到 12 小时后,其分叉协议Beethoven X 也遭受了类似的攻击,导致估计损失约 110 万美元Beethoven X 遭受的损失比 Balancer 更大!此次安全事件的总损失累计达到约 212 万美元

完整的攻击交易列表已收集在我们准备的文档中。请参考该文档以获取更详细的信息。

关于攻击者的一些观察

在分析每个网络发起的交易后,我们发现Fantom 上的攻击交易链与以太坊和 Optimism 上的交易链存在显著差异

具体来说,除了关键函数中的显著差异外,Fantom 上的攻击者利用了两种独特的技巧来避免被 MEV Bot 抢跑。此外,在 Fantom 上发动攻击的资金在攻击前 163 天就已经准备好

从上述观察中,我们可以推断:

0x5 结论

总而言之,这是一个微妙的漏洞,其根源在于向下取整逻辑。然而,利用此漏洞并非易事。具体来说,攻击者通过利用 linear 资金池中的向下取整问题,成功地提高了缓存代币费率,从而操纵了相应 boosted 资金池中的代币价格。

此事件也强调了及时通知那些从易受攻击来源分叉的项目的 Yet. 尽管 Balancer 已经发出警报,但针对分叉协议的攻击仍在继续,这凸显了这些分叉项目需要及时了解其源项目安全更新的必要性。然而,确保这些分叉项目及时收到通知仍然是社区面临的一个持续挑战。

此外,持续不断的攻击系列也凸显了主动威胁防御的重要性,这可以有效地帮助减轻潜在损失。

参考

Sign up for the latest updates
Weekly Web3 Security Incident Roundup | Feb 9 – Feb 15, 2026

Weekly Web3 Security Incident Roundup | Feb 9 – Feb 15, 2026

During the week of February 9 to February 15, 2026, three blockchain security incidents were reported with total losses of ~$657K. All incidents occurred on the BNB Smart Chain and involved flawed business logic in DeFi token contracts. The primary causes included an unchecked balance withdrawal from an intermediary contract that allowed donation-based inflation of a liquidity addition targeted by a sandwich attack, a post-swap deflationary clawback that returned sold tokens to the caller while draining pool reserves to create a repeatable price-manipulation primitive, and a token transfer override that burned tokens directly from a Uniswap V2 pair's balance and force-synced reserves within the same transaction to artificially inflate the token price.

Top 10 "Awesome" Security Incidents in 2025

Top 10 "Awesome" Security Incidents in 2025

To help the community learn from what happened, BlockSec selected ten incidents that stood out most this year. These cases were chosen not only for the scale of loss, but also for the distinct techniques involved, the unexpected twists in execution, and the new or underexplored attack surfaces they revealed.

#10 Panoptic Incident: XOR Linearity Breaks the Position Fingerprint Scheme

#10 Panoptic Incident: XOR Linearity Breaks the Position Fingerprint Scheme

On August 29, 2025, Panoptic disclosed a Cantina bounty finding and confirmed that, with support from Cantina and Seal911, it executed a rescue operation on August 25 to secure roughly $400K in funds. The issue stemmed from a flaw in Panoptic’s position fingerprint calculation algorithm, which could have enabled incorrect position identification and downstream fund risk.