ERC-4626通胀攻击及其缓解方法

本文深入分析了ERC-4626 Vaults中存在的通胀攻击漏洞,攻击者可以通过极少量初始存款和后续的“捐赠”操作,操纵Vault的份额计算,从而窃取后续存款人的资产。文章详细解释了攻击原理、步骤,并通过实例进行了说明,同时探讨了针对此漏洞的多种防御措施,例如使用ERC4626 Router、内部跟踪总资产、创建“死亡份额”以及在初始化时注入初始资金等。

ERC-4626 通货膨胀攻击以及如何缓解它。

(如何通过 1 wei 的存款耗尽你的金库:分析一种微妙但具有毁灭性的智能合约漏洞)

现在,让我们一起设想一下——一个新部署的金库,看起来很安全,等待用户存款。几分钟之内,攻击者只存入了 1 wei ——这个数额小到几乎可笑。但是,通过精确和计算好的一系列交互,他们拿走了比他们投入的价值更多的价值,让合法的用户持有毫无价值的份额,并破坏了信任。

这不是虚构的——这是一个潜伏在许多看似“安全”的智能合约架构中的真实漏洞。

在这项分析中,我们深入研究这种精妙但危险的漏洞,它滥用金库份额机制、捐赠时机和奖励同步,以耗尽诚实用户的价值。我们分解它是如何发生的,为什么它有效,以及你如何使你的合约免受攻击

ERC-4626 金库是高效的,但如果设计不当,它们很容易受到通货膨胀攻击。让我们一步一步地来。

什么是 ERC4626?

ERC-4626 是以太坊中代币化金库的标准。金库就像一个智能合约,持有代币并允许用户存款和取款。

把它想象成一个代币的银行账户:

  • 你存入一种代币(例如 USDC),金库会给你份额作为回报。这些份额代表你在金库总资产中的份额。
  • 当你取款时,你退回你的份额,金库会把相关的代币返还给你。

该标准确保所有金库以一致的方式工作,从而使 DeFi 应用程序更容易与它们交互。

理解 ERC-4626 通货膨胀攻击是如何运作的

金库通货膨胀攻击:小猪存钱罐抢劫案

把金库想象成一个特殊的数字小猪存钱罐(称为“金库”),人们可以在其中存钱。这个小猪存钱罐不是简单地跟踪每个人存入了多少钱,而是分发纸质票据(称为“份额”),这些票据代表了对银行中物品的所有权。

它通常如何运作

  1. 如果你是第一个把钱放进空的小猪存钱罐的人,你会得到与你投入的金额完全相等的票据。
  • 示例:你投入 10 美元,你得到 10 张票。

2. 如果你稍后存款,小猪存钱罐会这样计算你的票:

  • 你的票 =(你的存款 × 当前总票数)÷ 当前总金额
  • 示例:如果银行里已经有 100 美元和 100 张票,你存入 50 美元,你得到:(50 美元 × 100)÷ 100 美元 = 50 张票

3. 当你想取回你的钱时,你退回你的票,并获得你应得的份额:

  • 你得到的钱 =(你的票 ÷ 总票数)× 银行里的总金额

通货膨胀攻击分步指南

以下是一个狡猾的人(我们称他们为“Bob”)如何窃取你的钱:

  1. 第一步:Bob 看到你即将把 100 美元存入一个全新的空的小猪存钱罐。Bob 迅速跑到你前面,只存入 1 美分。
  • Bob 现在有 1 张票(0.01 份额)
  • 银行总额:0.01 美元
  • 总票数:0.01

2. 通货膨胀步骤:然后 Bob 做了一些棘手的事情。Bob“捐赠”了 100 美元给这个小猪存钱罐,但没有得到任何新票。这与正常的存款不同。

  • Bob 仍然只有 0.01 张票
  • 银行总额:100.01 美元
  • 总票数:0.01

3. 你的存款:现在你来了,存入了你的 100 美元。小猪存钱罐计算你的票:

  • 你的票 =(100 美元 × 0.01)÷ 100.01 美元 = 0.00999…(四舍五入为 0 张票)
  • 你的 100 美元得到零票!

4. 盗窃:Bob 现在使用他们的 0.01 张票提款,这占所有现有票的 100%。

  • Bob 得到:(0.01 ÷ 0.01)× 200.01 美元 = 200.01 美元
  • Bob 总共投入了 100.01 美元,但取出了 200.01 美元
  • 你的 100 美元不见了!

使用饼干罐的例子

假设你正在打开一个全新的饼干罐,人们可以安全地存放他们的饼干。当有人把饼干放进去时,他们会得到票,显示他们拥有多少饼干。这基本上就是“金库”——一个安全的地方来存储数字货币(比如加密货币),在那里你会得到特殊的代币(称为“份额”),代表你的所有权。

  1. 首先,Alice 想把 100 块饼干放入这个全新的饼干罐。
  2. 在她可以这样做之前,一个狡猾的人(攻击者)迅速先放入了一个饼干。
  3. 现在,攻击者秘密地将 100 多个饼干放入罐中,而不拿走它们的票。
  4. 当 Alice 终于放入她的 100 块饼干时,发生了一些奇怪的事情。
  • 数学计算表明她得到 100 ÷ 101 = 0.99 张票。

5. 攻击者现在拿走了所有的饼干,因为他们是唯一拥有票的人。

攻击者如何几乎不花任何代价就获得大量份额?

关键问题是当金库新建或接近空置时,份额是如何计算的

在 ERC-4626 中,用于计算份额的公式基于金库中的总资产与已经发行的总份额之间的关系。公式如下:

用于在 ERC-4626 中计算份额的公式

其中:

  • deposit amount:用户存入的代币数量。
  • total shares:金库已发行的份额总数(包括已发给所有用户的所有份额)。
  • total assets:金库持有的代币总价值。
  1. 首先,他们只存入 1 wei(可能的最小金额)
  • 当金库为空时,计算很简单:他们用 1 wei 获得 1 份额
  • 这是因为金库使用上述公式。
  • 由于还没有资产,所以只是 1 ∗ 1 / 1 = 1 份额

2. 然后,他们秘密地将更多的代币直接发送到金库

  • 他们不通过正常程序存款
  • 这增加了金库的总资产,但没有改变份额的数量
  • 金库的计算没有区别对待这些“捐赠”代币

3. 这为下一个存款人创造了一个完美的陷阱

  • 当其他人试图存款时,计算结果对他们不利
  • 该公式现在看起来像:

  • 由于 donatedAmount 与 1 相比非常大,因此他们几乎没有获得任何份额

例如,如果攻击者在他们的 1 wei 存款后捐赠了 100 个代币:

  • 当有人存入 100 个代币时,他们得到

  • 攻击者仍然拥有他们的 1 份额
  • 攻击者可以提取所有内容,因为他们拥有所有份额

为什么这有效

这之所以有效,是因为金库在计算份额时会向下舍入。攻击者本质上是在操纵公式中的分母,使其他所有人的存款几乎一文不值,同时保持他们微小的存款价值一切。

此攻击的关键在于,金库以相同的方式对待所有传入的代币,无论它们是通过正确的存款进入还是直接发送到合约的。这允许攻击者在不获得更多份额的情况下人为地抬高金库的资产,从而使他们现有的份额价值一切。

分析 code4rena 上 prePO 竞赛的提交

查看 solidit 上的此提交,我们看到它与我们的讨论相似。 这是在 prePO 在 code4rena 上的审计竞赛中发现的。 它被提交为高风险发现。 这就是为什么我最初称这种漏洞非常危险的原因。

Cyfrin Login | Solodit \ \ Profiles by Cyfrin\ \ solodit.cyfrin.io

提交中的攻击摘要

此提交描述了一个类似于我们之前讨论的通货膨胀攻击。以下是简化的细分:

  1. 初始存款 (2 wei)
  • 攻击者存入 2 wei,这足以铸造 1 份额(因为存在最低存款额)。

2. 操纵份额价格(大规模转移)

  • 然后,攻击者向 _strategyController 发送大量(100 万个代币)以夸大份额价格
  • 这类似于操纵金库的资产,使其看起来份额的价值高于实际价值。份额价格上涨,但这种情况发生得不公平

3. 后续存款人(10,000 个代币)

  • 新的存款人尝试存入合理数量(10,000 个代币)。
  • 但是,由于之前的通货膨胀,他们的存款不会铸造任何份额
  • 攻击者现在控制着所有份额,而后续存款人收到 0 份额,以换取他们的 10,000 个代币。

将其与我们对 ERC-4626 通货膨胀攻击的讨论联系起来

此攻击直接利用了用于计算份额的数学公式,以及份额可以通过操纵金库中的总资产来人为抬高的事实。以下是相关的方式:

  1. 抬高份额价格
  • 就像在 ERC-4626 金库中一样,攻击者操纵金库的总资产以抬高份额的价格。这类似于我们之前示例中的攻击者收到少量存款的 1 份额,而金库持有更多的价值。
  • 在这种情况下,攻击者使用大规模转移到策略控制器,从而抬高金库的资产,从而抬高份额的价值。

2. 后续存款人不发放份额

  • 在份额价格被抬高后,后续存款人处于劣势。他们存入大量(例如,10,000 个代币),但收到 0 份额
  • 这类似于在我们之前的示例中,第一个存款人获得不公平的份额(以很小的存款获得 1 份额),而后面的存款人没有获得与其较大存款相对应的份额。

3. 攻击者的优势

  • 就像在 ERC-4626 通货膨胀攻击中一样,此方案中的攻击者在操纵金库的状态后最终控制了所有份额。这使他们能够在需要时提取远多于他们应该提取的金额

提交中提出的缓解措施

现在,让我们分析推荐的缓解措施,以及它们如何解决 ERC-4626 金库中的漏洞:

  1. Uniswap V2 的解决方案 - 将第一个 LP 代币发送到零地址
  • 这个想法是为了防止初始操纵者获得对金库份额的过多控制权。
  • 通过在金库没有份额时(即当 totalSupply() == 0 时)将第一组代币(或份额)发送到 零地址,它本质上从一开始就稀释了份额供应
  • 这可以防止单个恶意用户从一开始就收到不公平的大量份额分配,这是我们讨论的攻击的直接对策。

2. 确保非零份额铸造

  • 一个简单的检查require(_shares != 0, "zero shares minted");)确保如果没有份额要铸造,该函数将失败。这将防止在进行了存款的情况下发放 0 份额的情况,攻击者利用这种情况来接管金库。

3. 用于初始化的外围合约

  • 使用一个外围合约组合 initialize()deposit() 函数的想法可以确保金库在其他任何人可以存款之前,通过一些存款和股份正确初始化
  • 这确保了金库的状态免受初始操纵,并避免了单个用户可以不公平地支配份额分配的情况。

分析 code4rena 上 GoGoPool 竞赛的提交

我们可以在 code4rena 中看到 GoGoPool 竞赛 的另一项提交。

此案例研究说明了生息代币实现中常见的漏洞模式,即可以利用合约的初始状态。对于使用 ERC4626 或类似金库标准的 DeFi 协议来说,尤其重要的是了解此攻击向量并实施适当的初始化程序。

该报告详细介绍了 GoGoPool 的 ggAVAX 代币实现中的一个高严重性漏洞,该漏洞允许恶意的第一个存款人人为地膨胀份额价格,并从随后的存款人那里窃取资金。

核心漏洞

该漏洞存在于 ERC4626 金库实现中,其中资产 (AVAX) 和份额 (ggAVAX) 之间的汇率计算为份额的 totalSupplytotalAssets() 之间的比率。攻击按以下方式进行:

  1. 攻击者抢先创建金库
  2. 存入最小数量 (1 WEI) 的 AVAX 以获得 1 份额
  3. 将大量 WAVAX 直接转移到金库
  4. 调用 syncRewards() 以更新帐户
  5. 由于份额数量很少,而资产数量很大,因此份额价格严重膨胀

影响

该报告确定了两个严重的后果:

  1. 资金盗窃:攻击者可以提取比他们存入的资产多得多的资产,从而有效地从随后的存款人那里窃取资产。
  2. 拒绝服务:小额存款人根本无法存款,因为他们的存款会由于夸大的汇率而转换为零份额,从而触发 ZeroShares() 还原。

概念证明

该报告包括一个全面的 Foundry 测试,证明:

  • Bob 存入 1 WEI,然后捐赠 1000 AVAX
  • Alice 存入 2000 AVAX,但仅收到价值 1500 AVAX 的份额
  • Bob 提取 1500 AVAX(从 Alice 那里窃取 500 AVAX)
  • 低于 1000 AVAX 的小额存款完全还原

技术细节

该漏洞利用了实施的两个具体方面:

  1. convertToShares() 中的份额价格计算,该计算使用总供应量与总资产的比率
  2. syncRewards() 中的奖励周期时间,它允许攻击者在条件有利时快速更新帐户

缓解

推荐的解决方案是在初始化期间用初始资金为金库播种,从而更难以操纵份额价格。这通过将初始存款作为合约初始化的一部分来防止抢先交易。

该报告已得到 GoGoPool 团队的确认,并且该漏洞已通过实施推荐的初始化存款来缓解。

如何防御这种攻击

从 opezeppelin 的博客 针对 ERC4626 通货膨胀攻击的新颖防御 中,以下是防御这种攻击的一些方法。

使用 ERC4626 路由器

这是一种相对简单的方法,但它可能只是规避问题,而不是直接解决问题。

在内部跟踪总资产

第二种策略旨在通过在内部跟踪金库持有的资产来消除直接转移的影响。这意味着捐赠的代币不被考虑在内,这有效地消除了通货膨胀攻击的风险。

创建“死亡份额”

该策略的灵感来自 Uniswap V2,它在首次存入流动性时创建了死亡 LP 份额。在 ERC4626 金库中,可以通过在首次存款/铸造时铸造死亡份额来实施类似的方法。

在该博客中,你将找到每种缓解措施的优缺点。

关于死亡份额,你将在 此处 找到完整的讨论。

我们还可以从我们分析的提交中看到一些缓解措施和建议。

此分析表明,DeFi 中微小的数学错误可能有多么危险。微小的 1 wei 差异——看起来无害——可以打开严重漏洞的大门,耗尽价值或阻止用户公平访问。

该课程是什么?永远不要因为你的数学看起来精确就认为它是安全的。金库、份额计算和定价逻辑都需要像潜在的攻击点一样进行测试——因为它们确实如此。

如果我们希望 DeFi 是安全且值得信赖的,我们必须像对待重要的事情一样对待即使是最小的细节。因为在这个领域,它们确实非常重要。

我喜欢称之为小数字,大风险

感谢你今天加入我。下次见。

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

0 条评论

请先 登录 后评论
CoinsBench
CoinsBench
https://coinsbench.com/