900万美元yETH漏洞剖析:16 Wei如何铸造出万亿天量代币

本文详细分析了2025年11月30日针对Yearn Finance yETH池的900万美元攻击事件。攻击者仅存入16 Wei(约4.5e-17美元),通过利用协议缓存存储状态未重置的关键漏洞,成功铸造了235 septillion(41位数)yETH代币,成为DeFi史上资本效率最高的攻击之一。

900万美元yETH漏洞剖析:16 Wei如何铸造出万亿天量代币

2025年11月30日,Check Point Research检测到针对以太坊上Yearn Finance yETH池的关键漏洞攻击。数小时内,攻击者从协议中盗取了约900万美元。攻击者仅存入16 wei(约合0.000000000000000045美元),却铸造了天文数字般的代币——235 septillion yETH(一个41位数)。这成为DeFi历史上资本效率最高的攻击之一。

漏洞成因:缓存存储缺陷

此次攻击利用了协议管理内部记账方式的一个关键缺陷。yETH池为了节省Gas成本,将计算值缓存在名为packed_vbs[]的存储变量中。这些变量存储虚拟余额信息,用于告知协议池中存在多少价值。当资金池被完全清空时,漏洞显现:主供应计数器正确归零,但缓存的packed_vbs[]值从未被清除。

攻击执行过程

攻击分三个阶段执行:

  1. 攻击者使用闪电贷资金进行了超过十次存款-取款循环,每次迭代故意在packed_vbs[]存储中留下少量残值。
  2. 攻击者提取所有剩余流动性,使供应量归零,而缓存值仍包含累积的虚增余额。
  3. 攻击者仅跨八个代币存入16 wei。协议检测到供应量为零,触发了其“首次存款”逻辑,该逻辑从存储中读取缓存值。结果,协议没有根据实际存入的16 wei铸造代币,而是读取了累积的虚增值,铸造了数万亿的LP代币,使攻击者控制了整个资金池。

背景:yETH生态系统

协议架构

Yearn Finance的yETH是一种流动性抵押代币,代表一篮子基于以太坊的流动性抵押衍生品(LSD)。该协议包含三个主要组件:

  • yETH代币 – 具有铸造者权限的标准ERC20代币
  • yETH池 – 加权稳定交换AMM(自动做市商)池
  • 汇率提供者 – 为各种LSD提供汇率的预言机合约

池合约实现了一个基于加权池机制的复杂数学不变式(类似于Balancer),并采用了Curve风格的虚拟余额进行Gas优化。

资金池核心机制

与简单的恒定乘积AMM(x × y = k)不同,yETH池使用了一个复杂的不变式,考虑了:

  • 多种资产(最多32种)
  • 每种资产的加权比率
  • LSD的汇率(wstETH、rETH、cbETH等)
  • 虚拟余额计算公式:vb_i = balance_i × rate_i / PRECISION

池将这些虚拟余额存储在状态变量中,以避免每次操作都重新计算——这一Gas优化措施成为了漏洞的来源。

漏洞:不完整的状态清理

核心错误

漏洞存在于两个函数之间的交互中:remove_liquidity()add_liquidity()

remove_liquidity()(第590-654行)中:

  • 问题:当所有LP代币被销毁(supply == 0)时,虚拟余额按比例递减,但从未显式重置为零。由于四舍五入,微小的金额残留在self.packed_vbs[]中。

add_liquidity()(第523-528行)和_calc_vb_prod_sum()(第729-744行)中:

  • 致命缺陷:这些函数从存储中读取self.packed_vbs[asset],期望在“首次存款”场景下其值为零。然而,经过多次存款/取款循环后,这些存储槽包含了从未重置的累积残值。

攻击交易:技术逐步分析

第一阶段:资金获取 攻击者通过Balancer和Aave的闪电贷借入资产,获得了wstETH、rETH、WETH、ETHx和cbETH,无需前期资本。

第二阶段:状态污染 攻击者执行了多次存款-取款循环,以在packed_vbs[]存储中累积残值。每个循环将资产存入金库和yETH池,然后提取部分资产。虚拟余额递减但从未完全重置。

第三阶段:池清空 攻击者销毁了所有剩余的LP代币,设置self.supply = 0,而self.packed_vbs[]保留了累积值且未重置

第四阶段:漏洞利用 攻击者跨所有支持的代币存入最少的wei金额。协议将此视为初始存款并读取了过时的存储值,铸造了数septillion的yETH代币,而不是根据实际微小存款计算。

第五阶段:资金提取 攻击者将铸造的yETH代币在Balancer池中兑换为WETH,并从池中提取底层资产(sfrxETH、wstETH、ETHx、cbETH、rETH、apxETH、wOETH、mETH)。

第六阶段:清理 攻击者通过Uniswap V3和其他DEX将所有盗取的资产转换为ETH,偿还了所有闪电贷及费用,并将一部分资金发送至Tornado Cash进行洗钱,同时保留剩余部分作为利润。

设计缺陷

yETH池持有多种具有不同价值的LSD,例如:

  • 1 wstETH ≈ 1.15 ETH
  • 1 rETH ≈ 1.08 ETH
  • 1 cbETH ≈ 1.00 ETH

为了计算应给您多少LP代币,池需要:

  1. 获取每个代币的汇率(计算成本高!)
  2. 计算:virtual_balance = actual_balance × rate / PRECISION
  3. 对所有虚拟余额求和
  4. 将此用于不变式计算

每次操作都这样做非常消耗Gas,因此池改为:

  1. 在您存款/取款时计算一次
  2. 将结果存储在packed_vbs[]
  3. 在未来的计算中重用此缓存值

未重置时的错误场景supply == 0时代码的假设:packed_vbs[]为零,意味着首次存款到全新池。 但在完全取款后实际发生的情况:prev_supply == 0,而packed_vbs[]包含先前操作的残余状态。

结论

yETH漏洞是利用微妙的状态管理漏洞的典范。攻击者展示了对于以下方面的深刻理解:

  • 协议的数学不变式
  • 存储布局和状态持久性
  • 如何在多个交易中操纵状态
  • 如何以最小资本最大化影响

对于防御者而言,此次攻击强调了复杂系统的正确性需要明确处理所有状态转换,而不仅仅是理想路径。一个缺失的状态重置——在1000多行代码中的一个疏忽——导致了900万美元的盗窃。

随着DeFi协议结合新颖的AMM设计和数学优化而变得越来越复杂,此类微妙漏洞的攻击面也在扩大。唯一的防御措施是严谨的工程规范:明确的状态管理、全面的测试,以及谦逊地假设如果某事可能出错,最终总会有人找到利用它的方法。

如何预防此类攻击

链上安全必须从事后取证演进到实时预防

  • 在执行前模拟交易,以捕获异常的代币铸造比率(16 wei存入 → 数septillion输出是不正常的)
  • 跨交易序列跟踪状态——此次攻击需要10多次存款/取款循环来污染packed_vbs[]。单笔交易监控会错过它
  • 当出现耗尽模式时自动阻止执行,而不仅仅是在事后发出警报

教训:一个缺失的状态重置——当供应量归零时packed_vbs[]未被清除——使得整个攻击成为可能。复杂的DeFi系统需要能够理解协议逻辑的运行时保护,而不仅仅是基于签名的检测。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计