Back to Blog

#6:Hundred Finance事件:引发针对漏洞分叉协议的精准攻击浪潮

Code Auditing
February 16, 2024
6 min read

2023年4月16日,Compound V2 的分叉项目 Hundred Finance 遭到攻击,导致约 740 万美元的损失。此次攻击涉及两个主要问题:

  • 一个精度损失问题(舍入错误问题);
  • 一个空市场问题,这使得黑客能够操控 exchangeRate(汇率)。

根据 DeFiLlama 的数据,Compound V2 是被分叉次数最多的借贷协议,拥有超过 100 个分叉版本。其合约经过 OpenZeppelin 审计且久经考验,被认为是安全的。然而,Hundred Finance 攻击事件凸显了精度损失(尤其是在流动性不足的情况下)如何严重影响 DeFi 协议的安全性,并在 Midas 和 Radiant 等知名分叉项目中引发了一连串类似的攻击浪潮。

为了更深入地了解,建议您查阅完整的分析报告。我们在下方提供了该事件的简要介绍,并将其列为 2023 年十大安全事件之一。

背景

Hundred Finance 概述

Hundred Finance 是 Compound v2 的一个分叉,运行在多个主网上,并使用 Chainlink 预言机。与传统金融借贷不同,像 Compound 和 Aave 这样的 DeFi 借贷协议不允许超额抵押借贷。 简单来说,如果您存入价值 100 美元的代币 A,您只能借出价值低于 100 美元的资产。根据大多数协议的风险控制系数,此比例通常在 50% 到 80% 之间。

对于借贷协议而言,常见的攻击方法包括价格操纵和重入攻击。值得注意的是,Hundred Finance 之前曾经历过一次 2022 年 3 月的重入攻击,但本次事件创造了一个新的攻击向量。

hToken

从 Compound 和 Aave 分叉而来的借贷协议会为每个底层代币(抵押品)创建一个相应的会计代币。对于 Hundred Finance:

  • USDC 对应 hUSDC
  • WBTC 对应 hWBTC

底层代币与 hToken 之间的汇率被称为 exchangeRate

  • 当存入资产时,用户应调用 hToken 的 mint() 方法。
  • 当提取资产时,用户应调用 hToken 的 redeem() 方法。

exchangeRate

以下是计算 exchangeRate 的公式: image

其中:

  • getCash():该 hToken 合约所拥有的底层代币余额总量。这是一个可以被操纵的关键参数。请记住这一点。
  • totalBorrows():当前市场借出的底层代币总量,也是市场供应方累积利息的基础金额。
  • totalReserves():储备金是每个 hToken 合约中的会计条目,代表了历史利息的一部分,这些资金会被留作现金,可以通过协议治理进行提取或转移。
  • totalSupply():当前在该 hToken 市场中流通的代币数量。

注意:hToken 和底层资产(例如 dai 与 hDai 或 eth 与 hEth)之间的 exchangeRate 起始值为 0.020,并以等于复合市场利率的速率增长。

清算

为了防止坏账,借贷协议允许任何用户清算他人的债务。让我们通过以下示例进行说明:

  1. Alice 存入价值 100 美元的 BTC,并借出价值 70 美元的 ETH。
  2. 如果 ETH 价格上涨或 BTC 价格下跌,Alice 的资产可能会达到清算阈值。
  3. Bob 可以使用一定数量的 ETH 来清算 Alice 的 BTC,使 Alice 的债务回到健康水平,从而确保协议资金的安全(协议会奖励发起清算的用户)。

清算并非此次攻击的重点,但它参与了攻击过程。在这里,我们只需要知道任何用户都可以用某一种代币清算他人的债务,这会减少相应的 hToken。

漏洞

精度损失问题

黑客通过 redeem() 提取抵押品时,导致扣除的 hToken 数量计算结果为 1.99999992(非常接近 2 但小于 2)。当使用 truncate() 函数转换为整数时,向下取整导致最终结果变为 1。

exchangeRate

如前所述,exchangeRate 的计算涉及 getCash(),即 hToken 合约持有的底层余额。通过直接向合约转入底层代币(不进行 mint,仅进行转账),黑客可以操纵 exchangeRate 然而,需要注意的是,仅凭这个汇率问题并不会破坏协议的安全性;黑客无法单独从中获利。 在本次攻击中,这一漏洞主要被用来放大黑客的收益,使其能够迅速耗尽资金池。否则,攻击将从一次决定性的打击变为一系列微小的消耗,需要进行无数次迭代才能产生显著影响。

简而言之,精度损失是此次攻击的核心问题。

攻击过程

以下是此次攻击的交易,我们将使用 Phalcon Explorer 来分析这一复杂的交易。

交易:0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451

  1. 通过闪电贷从 Aave V3 借出 500 WBTC。

  2. Redeem(赎回)之前获得的所有 hWBTC,将 hWBTC 的 totalSupply 重置为 0。

此前的目标是利用闪电贷准备储备资金,并将 hWBTC 重置为一个新市场。

  1. Create(创建)第二个攻击合约(以下称为 攻击合约 2),并将所有 WBTC (500.30063816 WBTC) 转入该合约。

  2. 使用 4 WBTC Mint() hWBTC,生成 200 hWBTC。

  3. Redeem() 199.99999998 hWBTC,使 hWBTC 总量剩余 0.00000002(2 wei hWBTC)。

  4. 将所有 WBTC (500.30063816 WBTC) 转入 hWBTC。注意,直接转账不会增加 hWBTC 数量;这可以被视作向资金池捐赠 WBTC。此步骤的主要目的是操纵前面提到的 exchangeRate。此时,hWBTC 的 totalSupply 仍然是 2 wei hWBTC,但现在却拥有 500.30064194 WBTC,使得 exchangeRate 变成了最初的数百倍。

  5. 从 hETH 市场借出 1021 Ether。

  6. Redeem() 50030063815 WBTC,计算后本应扣除 1.9999992 hBTC,但由于精度损失,实际仅扣除了 1 hBTC,造成了巨大的精度损失(接近 50%)。 此时,黑客拥有 500 WBTC + 1021 Ether,成功获利 1021 Ether

  7. 攻击者 liquidate()(清算)剩余的 hWBTC,totalSupply 重置为 0,为继续攻击其他市场做准备。鉴于 hWBTC 内的绝大部分 WBTC 已被提取,黑客仅用 0.000002 Ether 就完成了此操作。

  8. 继续攻击其他市场,耗尽整个协议。

  9. 偿还闪电贷给 Aave。

安全建议

借贷协议的缓解措施

此问题十分普遍,尤其是对于 Compound 和 Aave 的分叉协议。一种积极的预防方法是,在启动新市场时,预先铸造少量会计代币,以确保 totalSupply 永不归零

精度损失问题的缓解措施

为了更好地规避由精度损失引起的一系列问题,在实践中设置最小值是一个有效的方法。这种策略有助于避免在处理极小数值时因精度损失而产生的重大影响。

阅读本系列的其他文章:

Best Security Auditor for Web3

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

BlockSec Audit