Back to Blog

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

Code Auditing
September 14, 2023
12 min read

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

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

  1. 第一个错误用于推高代币费率,是利润的根本原因。没有它,盈利将不可行。

  2. 第二个错误通过平衡 bb-a-代币的债务来实现攻击。如果没有它,由于 bb-a-代币的流动性差,攻击将失败,因为没有其他途径可以获取这些代币(除非攻击者以某种方式设法获得它们)。

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 支持多跳交易,也称为 batchSwap,它利用注册到 Vault 的所有资金池中的最佳价格。具体来说,Vault 提供了 batchSwap 函数来促进多跳交易。

Balancer 资金池中的 flash swap 消除了执行交易通常所需的持有任何输入代币的需要。相反,在发现失衡后,您可以指示 Vault 执行交易,然后获得奖励。

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

以下我们将简要介绍与此漏洞相关的几个资金池概念。

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

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

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

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

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

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

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

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

  • bb-a-USDC(由 USDC 和包装的 aUSDC 组成)
  • bb-a-USDT(由 USDT 和包装的 aUSDT 组成)
  • bb-a-DAI(由 DAI 和包装的 aDAI 组成)

具体来说,bb-a-USD 是一个 Composable Stable Pool 的集合,其中包含三个不同 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 是一个常量值: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 资金池中使用 bb-a-USDC(作为 BPT)交易 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
  2. 偿还闪电贷,最终利润为:

    • 114,324 DAI
    • 253,461 USDT
    • 0.970495 aUSDC

值得注意的是,攻击者在步骤 2 中从 bb-a-USDC 资金池中消耗了 USDCaUSDC,这将使步骤 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 机器人抢跑。此外,Fantom 攻击中使用的资金是在攻击发生前 163 天准备好的。

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

  • 至少有两位不同的攻击者参与其中。
  • Fantom 上的攻击者是一位经验丰富的惯犯。

0x5 结论

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

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

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

参考

Sign up for the latest updates
The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis
Security Insights

The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis

This BlockSec deep-dive analyzes the KelpDAO $290M rsETH cross-chain bridge exploit (April 18, 2026), attributed to the Lazarus Group, tracing a causal chain across three layers: how a single-point DVN dependency enabled the attack, how DeFi composability cascaded the damage through Aave V3 lending markets to freeze WETH liquidity exceeding $6.7B across Ethereum, Arbitrum, Base, Mantle, and Linea, and how the crisis forced decentralized governance to exercise centralized emergency powers. The article examines three parameters that shaped the cascade's severity (LTV, pool depth, and cross-chain deployment count) and provides an exclusive technical breakdown of Arbitrum Security Council's forced state transition, an atomic contract upgrade that moved 30,766 ETH without the holder's signature.

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026

This BlockSec weekly security report covers four attack incidents detected between April 13 and April 19, 2026, across multiple chains such as Ethereum, Unichain, Arbitrum, and NEAR, with total estimated losses of approximately $310M. The highlighted incident is the $290M KelpDAO rsETH bridge exploit, where an attacker poisoned the RPC infrastructure of the sole LayerZero DVN to fabricate a cross-chain message, triggering a cascading WETH freeze across five chains and an Arbitrum Security Council forced state transition that raises questions about the actual trust boundaries of decentralized systems. Other incidents include a $242K MMR proof forgery on Hyperbridge, a $1.5M signed integer abuse on Dango, and an $18.4M circular swap path exploit on Rhea Finance's Burrowland protocol.

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026

This BlockSec weekly security report covers four DeFi attack incidents detected between April 6 and April 12, 2026, across Linea, BNB Chain, Arbitrum, Optimism, Avalanche, and Base, with total estimated losses of approximately $928.6K. Notable incidents include a $517K approval-related exploit where a user mistakenly approved a permissionless SquidMulticall contract enabling arbitrary external calls, a $193K business logic flaw in the HB token's reward-settlement logic that allowed direct AMM reserve manipulation, a $165.6K exploit in Denaria's perpetual DEX caused by a rounding asymmetry compounded with an unsafe cast, and a $53K access control issue in XBITVault caused by an initialization-dependent check that failed open. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit