收益聚合器的常见陷阱:Beefy 案例研究

  • mixbytes
  • 发布于 2024-01-25 20:32
  • 阅读 30

本文深入探讨了Yield Aggregators(收益聚合器)的安全问题,以Beefy Finance为案例,强调了DeFi项目中的多种安全风险和审计要求。作者讨论了收益聚合器如何通过策略实现收益最大化,并且指出了在计算收益、资产管理以及代币特性方面的潜在攻击向量。读者能够通过案例分析,更清楚地了解Yield Aggregators的复杂性与安全性。

作者:Daniil Ogurtsov - MixBytes的安全研究员

在本文中,我们将概述在收益聚合器中遇到的安全问题,这是DeFi中非常常见的一类项目。自行业诞生以来,它们已经走过了一段漫长的道路,并积累了丰富的安全技术和最佳实践经验。

本文旨在描述特定于收益聚合器的bug。由于它们具有独特的背景,因此安全审计可更详细和深入地考虑这些特点。额外的分析框架可以帮助发现更复杂的bug。

收益聚合器如何工作

来源:https://arxiv.org/pdf/2210.04194.pdf

DeFi项目通常需要大量的流动性来运作。流动性在行业中是有限的,项目竞争吸引流动性。因此,DeFi项目设计用以激励流动性提供者——以费用或代币铸造的形式。这些奖励取决于用户在这些DeFi项目中的活动,因此流动提供者的回报是波动的。

收益聚合器项目“聚合”了一些流动性提供者的选项,并提供一些额外的特性和工具:

  1. 他们构建“策略”——专门的智能合约,负责:
  • 确定收益将如何生成(在哪里、如何以及以哪种代币)
  • 将流动性交付到最终生成回报的智能合约
  • 提取并传递流动性回流动性提供者
  • 修改风险/回报特征(例如,通过折叠利用杠杆获取更多风险/回报)
  • 通过特殊的交易流最大化回报(以收取更多奖励的额外代币)
  • 优化回报交付(例如逐步出售奖励代币)
  • 考虑特殊情况(清算风险、紧急提款)。
  1. 他们以增长为导向运作。收益聚合器通常选择不承担不可永久性损失风险,并避免出现负回报的情况。因此,投资通常以LP代币的形式接受。在某些情况下,收益聚合器可能会提供单边存款的额外选项——有时可用于大流动性稳定币池(例如Curve上的稳定交换池)。

  2. 他们进行复利——奖励被每小时/每日再投资以提升进一步回报。这是大多数用户使用收益聚合器的主要原因。对所有流动性提供者同时在一次交易中再投资更为有效——在大多数项目中,这被称为“收割”。然而,这不仅仅是再投资,也是某些代理在积极回报时收取费用的时刻(策略构建者、收益聚合器本身、收割功能调用者)。

上述特征是任何收益聚合器的基础,但推广的产品可能有所不同。其中一些以收益聚合作为核心工具(如Yearn Finance、Beefy Finance),其他可能将其他产品推向用户,而将收益生成本身视为次要(如OUSD提供稳定币或Idle以分期的形式提供固定或杠杆利率)。这些特殊产品的转变将从我们的分析中排除。

主要安全分析原则

我们看到收益聚合器的两个基本组成部分使得安全分析变得特殊。

1) 通常它们有许多金库/策略——它们的设计和风险可能显著不同。

收益聚合器更愿意为其金库/策略的安全负责。因此,收益聚合器设计了内部审计、测试、监控的流程,以便在上线前对策略进行充分分析。此外,他们邀请外部策略构建者并激励他们扩展金库/策略的市场。

这与大多数DEX的情况不同,DEX中的对之间共享同一个智能合约,但可以有不可预知的代币被交易。DEX团队仅构建智能合约标准,但通常不对交易对中的代币负责。

相比之下,收益聚合器的金库/策略很少标准化——它们有不同的交易流、连接的DeFi项目和转移的代币。因此,更广泛的坏场景可能会出现。让外部审计人员分析一些金库(尤其是核心的)是一种正常的做法。

2) 独特的信任假设集。

金库有策略构建者和管理者。他们具有某些特权功能旨在有利于流动性提供者。但这些所有者可能是潜在的恶意行为者。因此,审计人员必须明确将所有者视为等待机会利用其特权的攻击者。

常见安全陷阱总结

操作会被操控的股份与基础代币之间的转换率

股份与接受的代币之间的转换是许多DeFi项目的痛点。错误的计算很容易被利用。

收益聚合器在这里并没有太大区别——它们通常铸造代币,Beefy Finance对此的描述非常准确“具有利息的代币化存款证明”。用户的余额并不会随着赚取的更多奖励而上升,但一个股份应该随着计入的奖励而代表越来越多的基础代币。这个转换率是动态的,可以被利用。

费率计算往往使用预言机或DEX。过度使用DEX是脆弱性的核心所在。这正是攻击者在黑客攻击最大的收益聚合器时所利用的地方。攻击者的目标是降低股份的转换率并提高后者的转换率。

对于分析的一般建议与许多使用DEX进行记账的项目相同——假设DEX可以在同一交易中设置为任何价格。如果能够在同一交易中使用不同的转换率进行存款和取款,则表明存在红旗。

依赖DEX可能有不同的形式。考虑PancakeBunny黑客(漏洞分析链接),该黑客向存款人收取每1 BNB收取3个BUNNY代币作为费用。然而,回报是以LP代币计算并需要转换为以BNB计价,而PancakeBunny在这一转换中犯了错误,这导致攻击者进行递归操控BUNNY铸造。

未能防护三明治攻击的交换

策略广泛使用交换。它们通常不只是想赚取协定费用;它们尝试最大化以额外代币获取的额外激励,如PancakeSwap为相关池的流动性提供额外CAKE交换。这些额外奖励从来不会长时间累积——策略在每次收割时会立即在DEX上进行交换。

攻击者可以利用这些以可预测的方式卖出代币的交易。他们进行三明治攻击,以增加金库的滑点并获得无风险的代币回报。

同样的问题出现在接受不同代币投资的金库中。金库在一开始会交换这些代币以获得用于生成收益的LP。

这里的建议很直接——控制交换中的风险容忍度,包括交换后最低接收代币的不变条件。

来自所有者的攻击

如前所述,最佳实践是将金库所有者/管理者视为恶意行为者。他们通常与收益聚合器团队没有关系。

这里有一些所有者/管理者通常可用的攻击向量:

  • 当前的金库/策略函数允许任意调用;
  • 当一个金库允许更改策略时。当之前的策略变得无效且需要更新时。有许多收益聚合器具有这一功能。这对所有方都非常方便,否则更新将需要从每一个流动性提供者那里提款。结果是,新版本可能会为所有者引入额外的隐藏权利;
  • 通过技巧人为提升管理人员的奖励/费用。

代币特定风险

对于许多收益聚合器,覆盖的活跃策略数量可以达到十个或数十个——受影响的项目集和传输的代币集独特。

偏离可预测ERC-20标准的多样化代币可能引入额外的漏洞向量。这在许多DeFi项目中都是这样的,但在这里,情况控制得更少,因为收益聚合器自身的性质暗示着场景的多样性,这使得出现不寻常的代币被认为是可能的。

所有类型的不寻常代币对于策略都是风险——通货膨胀/通货紧缩、重置、带息、可钩、具有奇怪的小数位、在函数调用时不返回任何值。这就是为啥在分析策略时特别关注代币。

这也是审计人员建议在所有关键功能上添加nonReentrant修饰符的原因——以消除意外钩子的风险。这是非常简单但极其有效的。

不良的余额管理

有时奖励的计算是错误的。有些奖励代币可能会被忽视,或者被阻塞在某些智能合约中。奖励值得进行强有力的测试,因为有许多容易出错的地方。

糟糕的金库生命周期设计

糟糕的金库设计可能低估金库出现的坏场景。有些只意味着存款和取款展示完整的生命周期。这显然不是真的。金库必须与更广泛的风险特征一起运作,必须设计风险缓解程序。产生收益的池可以被黑客攻击,借贷协议上的头寸可以被清算等。

团队必须检查是否嵌入特殊功能供所有者/管理者处理此类情况(暂停、紧急提款、管理流动性头寸和杠杆/折叠)。

值得注意的是,这是最难分析的主题之一,因为这不仅需要理解代码,还需要了解什么时候出错可能发生的各种场景。


在接下来的案例研究中,我们将以一个简单的金库为例,尝试从这些攻击向量的角度进行分析。

案例研究:评估Beefy Finance

在这里,我们将描述Beefy Finance金库以及它们如何处理攻击向量。

我们的例子是CAKE-BNB LP金库。

https://app.beefy.finance/vault/cakev2-cake-bnb

下面是该金库的智能合约系统示意图,包括资金流动。

这个Beefy金库关系到五个合约,其中三个是Beefy编写的:Vault、Strategy、BoostStaker。每个合约都有各自的角色。

Vault - 负责与用户的交互(接收LP和发送增长的LP)。每次存款都会铸造股份,每次提款都会销毁股份。这个合约是ERC20的,因此股份像普通代币一样可转让。金库是股份与LP之间转换逻辑的关键点。

https://bscscan.com/address/0xb26642B6690E4c4c9A6dAd6115ac149c700C7dfE

Strategy - 管理代币转移的整体逻辑。收割在这里进行——它应该1) 再投资增长的LP和2) 将以其他代币形式获得的奖励进行销售,在DEX上出售以获得token0和token1,将它们存入DEX交易对以将其转换为更多的LP。

https://bscscan.com/address/0xDE238C509bcCBCd91B90dE40dF3e25B43A131311

BoostStaker - 是一个中间合约,旨在通过将其一部分发送到veContract(如果该代币存在并且包括在策略中)来提升获得的代币奖励。这个Beefy策略使用了BoostStaker但没有将代币发送到veContract - 因此附加奖励实际上并没有进行耕作。

https://bscscan.com/address/0xd7c0c12c91750a6ef37580d44b0fd6af1068e615#code

MasterChef - 一个来自PancakeSwap的合约,接收LP,LP必须来自白名单,通常来自于一侧为CAKE代币的对。MasterChef持有约100万美元的CAKE余额并将其分配给LP的存款者。这是项目激励流动性提供的知名工具。这是策略中CAKE的来源。

https://bscscan.com/address/0xa5f8c5dbd5f286960b9d90548680ae5ebff07652#code

DEX - 策略并不评估CAKE代币的回报。为了不与其打交道,现金流中每个CAKE都会在DEX出售以获得更多的LP。

https://bscscan.com/address/0x10ed43c718714eb63d5aa57b78b54704e256024e

有时赚取的铸造代币(如我们例子中的CAKE)可以通过添加时间锁抵押到veContract以获得额外的铸造分发(BoostStaker模块)。但对于这个CAKE-BNB LP金库来说并不适用。

让我们逐个检查一些常见的攻击向量,并寻找一些论据来证明该金库在攻击中是安全的。

向量一:被操控的股份与基础之间的转换率

我们将展示一个简单的框架来分析转换率。我们将检查攻击者是否无法提取超过存入的金额。

步骤如下:

  1. 找出转换发生的函数;
  2. 将转换分解为可理解的公式;
  3. 分析每个元素在公式中的表现,检查攻击者是否有选项去操控这些元素。操控任何元素意味着操控整个公式的返回值,从而操控转换率。

处理这个问题的主要合约是Vault。

这是存入/提取函数的代码。

让我们将其分解为更简单的公式。

这些公式来自代码,旨在单独说明所有组件。某些行涉及到通货紧缩代币的风险(代币在传输过程中可能会丢失)。我们在公式中保留这一部分。

此外,你可能从代码中注意到,函数withdraw()还额外检查了Vault合约上的b - LP余额。目前我们将其忽略,但稍后在分析其他向量时将重新提及。我们找到了有趣的数学错误。

我们将集中在每个公式元素上,估计攻击者操控某个元素数字的可能性。同时,我们假设攻击者拥有无限资金并可以随时闪贷。攻击者的目标是提升[shares per LP](每个LP的股份)在存入时增加,并降低[share per LP](每个LP的股份)在提款时减少——这有可能让他们提取超过存入的资金(但不一定)。

现在让我们分析所有的元素:

  1. 已铸造股份总额

该参数在任何代币移动之前计算,攻击者无法通过其他函数铸造/销毁股份。此外,该参数作为合约变量存储,无需调用即可计算。

因此,这个元素是被保护的。

  1. Vault的LP余额 + Strategy的LP余额 + MasterChef上累积的LP

这些参数容易被提升——攻击者可以向这些合约发送代币,但这并不意味着会有什么危险。首先,攻击者无法撤回这些发送的代币。其次,在我们的情况中,攻击者提升了[shares per LP],但这些操控的收益少于平衡提升的成本。想象一下,提供100个股份,余额中有200个LP代币,转换率为0.5。首先,攻击者以当前费率存入100个LP代币。现在我们有150个股份和300个LP代币。然后,攻击者直接向余额发送150个代币。转换率变成150 /450 = 0.25。是的,攻击者成功地降低了[shares per LP],但这样的攻击不会带来利润。攻击者提取50个股份,但获得了450 *50 /150 = 150个LP代币,尽管花费是100个LP代币(存款)和150个代币(直接提升余额)。

因此,这个元素没有保护,但也不脆弱。

  1. 传输过程中丢失的LP百分比

在这里,金库试图处理通货紧缩代币。

这个元素是被保护的,攻击者通常无法在一笔交易中影响此参数,但对于重置代币某些操控是可能的。攻击者可以进行余额更新交易的抢跑交易,进而使同一序列的交易具有不同的转换率。然而,必须指出的是,收益聚合器优先不与重置代币打交道(像许多DeFi项目一样)。

因此,公式是防止攻击的。我们可以从中得出什么教训?

  1. 大多数数字在任何代币移动之前都被获得。
  2. 它很简单。
  3. 没有获取价格数据并且较少读取外部合约。
  4. 存款和提款的公式是相同的。

最后的话,在这里,你可能注意到这些公式并不完全相同。问题就在于传输过程中丢失的LP百分比。在存款中是乘法,而在提款中是除法。但在通货紧缩代币的背景下这没有问题。用户的损失是永远存在的:在存款时收到更少的股份,在提款时需要更多的股份。因此,这里的公式偏差是必要的。

向量二:未防止三明治攻击的交换

对于收益聚合器,有两个常见的地方存在不受保护的交换:

  1. 金库外部:存款和提款的代币转换。
  2. 金库内部:收割或其他操作的代币转换。

让我们来观察我们选择的CAKE-BNB金库的这两个区域。

存款和提款时的代币转换

从界面页面可以看到,这个金库允许存入和提取多个代币。

https://app.beefy.finance/vault/cakev2-cake-bnb

但是,金库合约仅接受一种代币类型——LP。

因此,转换在某些外部合约中发生。

这是Beefy描述的交易流。

这是这样的交易的示例。

https://dashboard.tenderly.co/tx/bsc/0x68d7210daadbf31c06a84fb9fe5d1b5ad15c8d9a00cc8b9de52119510119d5c0/debugger

从交易中,我们导出了处理交换的合约。

https://bscscan.com/address/0x10ab57c5889a00c497ce6be7ce142bb9a613e362#code

此处的交换通过DEX路由器经过每个地方实现AmountOutMin——该参数在交易初始化时以数据输入,因此是离线计算的。交易示例如证实该金额不是默认设置为零。这足以减轻三明治攻击的风险。

收割或其他操作时的代币转换

策略合约是处理这些交换的合约。在我们的策略中,交换用于转换从MasterChef获得的CAKE代币作为奖励。

如你所见,此处AmountOutMin被设置为零。因此,在发生重大滑点交换的情况下,它在前置运行中是脆弱的。但上下文是,在这里发生重大滑点交易的可能性不大——池的规模远大于平均CAKE收割的数量。此外,收割可以频繁发生,因为金库在Binance智能链上运行——这降低了在一笔交易中发生大量CAKE收割的可能性。

向量三:来自所有者的攻击

我们的CAKE-BNB金库使用Beefy标准来设置角色特权——所有金库是相同且相当安全的。

向量四:代币特定风险

在我们的金库中,代币相当常见且没有额外的风险。

向量五:不良的余额管理

金库处理简单代币,但保留了某些代码来减轻通货紧缩代币传输可能出现的意外情况。在我们的金库中并不存在这样的情况,但作为标准,它的代码会从策略迁移。代码应用余额检查,因此只有实际收到的代币才被计算。

我们发现了一个微小的错误,这可能导致对股东的错误提款计算。此情况看起来不严重,但有趣的是这是如何通过设计而可能的。

问题出现在这个金库函数中,以及它的用法。

此函数计算总的金库代币,并用来计算[share per LP]。它总结了Vault、Strategy上的LP余额和MasterChef上的累积LP代币。

必须满足两个条件:

  1. 金库和策略合约上有大量代币。
  2. LP是个通货紧缩代币(代码试图处理这些情况)。

在这种情况下,股东的提款将不正常。

回想一下这个函数。

让我们设想一个简单的场景。

我们有铸造的100个股份,两位股东各50。

我们从balance()函数返回200个LP代币,合约之间的分配为:

  1. Vault中50
  2. Strategy中50
  3. MasterChef中100

让我们应用传输时1%的燃烧率以处理通货紧缩代币。

想象一下第一个股东提取50个股份。

根据withdraw()函数,该股东将提取98.5个代币。

当第二个股东提取50个股份时,他们将获得96.05个代币。

结果是,他们持有相同数量的股份,但提取的LP代币不同。

这是如何发生的?

每个合约都从链中的下一个合约提款。

如果Vault合约拥有一些LP代币的余额,则它不会从Strategy中提款。Strategy也是如此——它试图优先以自身的资金支付,然后再撤回BoostStaker。依此类推。

“更深”合约余额中的LP代币在通货紧缩代币的情况中变得更昂贵。

应用1%的烧毁率以传输,MasterChef上的100个LP代币将在到用户钱包时需要进行4次传输,最终仅剩下96.05。

因此,第一位股东提取了“更便宜”的代币,这种转移的最小成本。

而第二位股东留下了“更贵”的代币,将在提取时经历4次传输。

在withdraw()函数中,关键参数r依赖于balance()函数。该函数累计三个余额组件,每个组件有效值不同。

对于通货紧缩代币,将不同合约上的代币余额相加是不正确的,因为它们需要不同数量的转移。

向量六:不良的金库生命周期设计

这个向量更适用于更复杂的策略。在我们的CAKE-BNB金库中,一切都是直接的。尽管如此,金库遵循内部标准并具有紧急功能。

控制风险的内部流程

一些收益聚合器采用内部程序来评估金库和策略。

Yearn通过许多步骤和高风险评分引入策略:

https://docs.yearn.finance/resources/risks/risk-score#strategy-risk-score

同样,Beefy Finance也适用:

https://docs.beefy.finance/safu-protocol/beefy-safety-score

总结

收益聚合器处理DeFi中可能发生的整个情况集。因此,审计人员必须特别关注金库的安全分析及其特殊向量。

我们只描述了最著名的安全问题,这些都是由收益聚合器特有的。显然,这里的所有智能合约漏洞都可能存在,并且具有破坏性。

  • 谁是MixBytes?

MixBytes 是一支由专家区块链审计员和安全研究员组成的团队,专注于为兼容EVM和基于子战略的项目提供全面的智能合约审计和技术咨询服务。请在X上关注我们,以保持对最新行业趋势和见解的关注。

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

0 条评论

请先 登录 后评论
mixbytes
mixbytes
Empowering Web3 businesses to build hack-resistant projects.