Beraborrow 协议在定价 LP 代币时,尽管采用了当时认为最安全的公式,但仍然受到了与赎回相关的定价问题的影响。
有时,即使你做对了所有的事情,仍然可能受到潜在的新型漏洞利用路径的影响。Beraborrow 团队就遇到了这种情况,尽管他们遵循了最佳实践,并使用了现有的最安全的 LP token 定价公式,但他们的借贷协议仍然受到了与赎回相关的定价问题的影响。
我们将在此讨论的问题是由 Recon 团队发现的(问题 H-7:StableBexFeed 在 LP 上使用预期套利后的定价,可能导致赎回时的大量损失),他们在为 Beraborrow 进行 Sherlock 协作审计时使用了人工审查,并通过模糊测试提高了其影响。
该问题与使用 Berachain 的原生交易所(BEX)feeds 对 Beraborrow 协议中提供的 LP token(作为抵押品)进行定价有关,这导致用户在赎回借款时会泄漏价值。
发现问题的 BEX price feeds 在开发和审计期间都经过了测试,但由于这里讨论的问题,最终在生产中实施了一种使用 Chronicle oracle 的替代定价方法。
Beraborrow 是建立在 Berachain 上的 Liquity V1 fork 的借贷协议,允许用户在不必出售资产的情况下获得流动性。用户通过将抵押资产存入 "Dens" 来实现这一点,这允许他们铸造 NECT,一种超额抵押的 stablecoin。
特别是对于此处讨论的漏洞而言,用户可以将 LP token(代表流动性池中的流动性头寸)作为其基础抵押品存入,这允许他们根据这些 token 进行借款,同时仍然可以从流动性池的 swap 费用中赚取收益。
Beraborrow 允许用户提供代表来自原生 Berachain BEX 交易所的流动性的 LP token。
由于该协议允许用户根据这些 LP token 进行借款,因此需要一种准确的定价机制,虽然起初看似微不足道,但我们将看到,定价一个代表具有可变 token 数量的池的 token 的额外复杂性最终是如何成为发现的漏洞的根本原因的。
在非对抗性环境中,LP token 的定价相对简单。它可以计算为池中资产的价值除以 LP token 的总供应量。
naive pricing = (V1 + V2) / LPtotalSupply
V1, V2 = asset value
LPtotalSupply = total supply of LP token
这给了我们每个 LP token 的按比例价值,但从历史上看,每个使用此定价公式的协议都遭到了利用,因为当以这种方式定价时,流动性池从根本上来说是可以操纵的,攻击者可以向池中的资产添加大量流动性以高估 LP token。使用闪电贷使攻击者更容易做到这一点。
假设池的储备金是不可操纵的使用朴素公式的项目也通过 view-reentrancy 遭到了利用(包括 Balancer 和 Curve)。
最终,唯一安全的 LP 定价机制包括对公平储备金进行定价,这些“公平”是因为它们无法通过闪电贷或临时强制失衡来操纵,这意味着它们忽略了套利前价值。
在这个 Secureum Workshop 中,Alex 展示了如何利用套利前的 LP 定价。
为了防止在定价 LP token 时出现上述类型的漏洞利用,协议通常使用公平储备金公式,该公式最初由 这篇文章 推广。
根据流动性池中资产的余额和 oracle 报告的 token 价格,这为我们提供了 LP token 的下限值:
Fair price = (2 * sqrt(r0 * r1 * p0 * p1)) / totalSupply
r0, r1 = balance of assets 0, 1 in the pool
p0, p1 = fair price of assets 0, 1
totalSupply = LP token supply
在以上公式中,可以使用 oracle 或 TWAP 找到其中一种池资产的公平价格。
该公式为我们提供了 LP token 的价值,我们可以在确定借款能力时使用该价值(对于给定数量的抵押品应收到的借款资产数量),最重要的是,该价值是不可操纵的,从而防止用户通过不平衡池来人为地提高价格,从而使 LP token 更有价值。
但是,正如我们将在下面看到的那样,此公式的缺点是,当对赎回进行定价时,它会泄漏价值(理想情况下,它应该高估 LP token 的价值,以避免为套利创造机会),从而允许用户在赎回 LP token 时获得泄漏的价值。
Beraborrow 团队在其协议中正确应用了公平储备金公式,以用于与 BEX 中的给定 LP 对关联的 price feeds,并包括了 view-reentrancy 的检查,这些检查可能允许在仅转移了某些 token 时更改储备金,从而导致定价异常。这意味着,通过所有指标,开设借贷头寸时 LP token 的计算价值都是正确的。
但是,在使用 Echidna fuzzer 进行了更深入的挖掘之后,Alex 能够证明,此定价公式在用于计算赎回价值时会泄漏大量价值。
理解此问题的关键在于注意到通过公平储备金公式定价 LP 会采用 LP token 可以拥有的最小理论价值。值得注意的是,如果流动性池具有不平衡或不具有对称储备金与价格比率的 token,则会低估 LP token 的价值。在这些情况下,公平储备金公式将低估 LP token 的价格,这对于评估头寸在开设时的价值是可以接受的,但在赎回时会导致问题。
以下面的示例为例:
假设我们有一个 1:1 USDC | USDT LP token。
该 token 代表的池是不平衡的,实际上具有 1.1USDC 和 0.91 USDT。
将上述 LP token 赎回为基础资产将导致 1.1 + 0.91 = 2.01 个资产,而公平价格公式给出的名义价值为 2 美元。
因此,在赎回中使用最小值(2 美元)会从协议中泄漏储备金不平衡造成的超额价值(0.01 美元),因为 LP token 被低估了。
为了确定价值泄漏的上限,我们使用了 Echidna 的 优化模式 来识别预期价格与可赎回价格之间最大可能差异的近似值,该差异已生成到 POC 中。
该设置包括使用 Balancer 提供的实际链上工厂(BEX 是 Berachain 上 Balancer 的实现)在 forked fuzz 测试环境中部署一个新池:
metastableFactory 是用于部署新池的 forked Balancer 工厂的实现。
在测试环境中部署了一个池之后,我们就可以公开以下目标函数 handlers,这些 handlers 允许 fuzzer 探索池上有意思的状态:
允许修改池状态的目标函数 handlers。
然后,可以使用以下函数返回一个值,该值允许 Echidna 优化使用公平价格公式计算的赎回价值与将泄漏的任何超额价值之间的差异:
优化函数首先从池中提取,然后检查提取的价值差异是否大于来自 oracle 的预期价值,然后返回两者之间的差异。
然后,使用 Recon Pro 作业运行器 执行了长时间的模糊测试运行,并使用我们的 echidna log scraper 工具生成了以下 POC:
Echidna 生成的调用序列,用于优化
sumOfValue
值和 fromOracle
值之间的差异,作为 Foundry 单元测试。
我们可以看到,当公式泄漏价值时,池中实际价值与 oracle 报告的价值之间的最大差异约为 1.81e21,这非常高。
应该注意的是,上述测试中的价值是假设性的,因为 fuzzer 正在将未限制的值传递给目标函数,使其能够达到更极端的值,这意味着实际中的最大影响会更小,因为它会受到攻击者可以供应的流动资金量的限制,从而使池不平衡。但是,该原理仍然成立,并表明价值可以被操纵,从而导致价值从协议中泄漏。此结果使我们建议 Beraborrow 团队不要继续使用链上定价机制。
我们希望我们已经证明,即使你认为自己可以把每件事都做对,但在将 DeFi 中的现有机制应用于新的用例时,你仍然可能会打开新型威胁载体的大门,这些威胁载体只能通过仔细审查才能发现。在本例中,该问题是手动发现的,但使用了模糊测试来提高可能的影响并证明可能损失的价值。
上述问题在竞赛中被归类为高影响,因为如果没有非常高的赎回费用,给定的抵押品可能会受到针对存款人的持续套利。
最终,鉴于上述链上定价的复杂性以及价值泄漏的风险,我们建议 Beraborrow 不要继续允许 BEX LP token 作为抵押品。
但是,通过与 Chronicle(一个用于定价 LP token 的 oracle)的合作,并通过将最低赎回费用提高到与所述费用的不准确性和延迟相匹配或超过的阈值,他们现在可以提供 BEX LP Token 作为抵押品,而不会使 Den 所有者面临套利风险。
如果你希望获得帮助来发现这些其他人可能错过的独特漏洞,结合熟练的安全研究人员和强大的不变性测试套件来保护你的代码库,请 联系我们!
- 原文链接: getrecon.substack.com/p/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!