2023年4月16日、Compound V2のフォークであるHundred Financeが攻撃を受け、約740万ドルの損失が発生しました。この攻撃には主に2つの問題が関与しています。
- 精度低下の問題(誤った丸め処理の問題)
- 空のマーケット。これにより、ハッカーは exchangeRate(交換レート) を操作可能となりました。
Compound V2は、DeFiLlamaによると最もフォークされているレンディングプロトコルであり、100以上のフォークが存在します。OpenZeppelinによる監査を受け、実戦で証明されたそのコントラクトは安全であると見なされてきました。しかし、今回のHundred Financeへの攻撃は、精度低下、特に低流動性下での精度低下が、いかにDeFiプロトコルのセキュリティに深刻な影響を与え得るかを浮き彫りにしました。これが引き金となり、MidasやRadiantといった著名なフォークでも同様のエクスプロイトが相次ぎました。
より深い理解のために、詳細な分析レポートを参照することを推奨します。以下に、本件を2023年のセキュリティインシデント・トップ10の一つとして取り上げ、簡潔に解説します。
背景
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 を計算する式は以下の通りです:

ここで:
getCash(): 当該hTokenコントラクトが保有する基礎資産トークンの残高。これは操作可能な主要パラメータです。この点を覚えておいてください。totalBorrows(): 市場から貸し出されている現在の基礎資産トークン量。市場の供給者に利息が蓄積される対象となる量です。totalReserves(): 準備金は、各hTokenコントラクトにおける会計上の記入項目であり、過去の利息の一部を現金として確保したものです。これはガバナンスを通じて引き出したり、移転したりすることができます。totalSupply(): 現在、当該hToken市場で流通しているトークンの総数。
注:hTokenと基礎資産(例:dai対hDai、eth対hEth)の exchangeRate は、0.020から始まり、市場の複利利率と同等の速度で増加します。
清算(Liquidation)
不良債権を防ぐため、レンディングプロトコルでは任意のユーザーが他者の債務を清算できるようになっています。以下の例で説明します:
- アリスが100ドル相当のBTCを預け入れ、70ドル相当のETHを借りる。
- ETHの価格が上昇するかBTCの価格が下落すると、アリスの資産は清算しきい値に達する可能性がある。
- ボブは一定量のETHを使用してアリスのBTCを清算し、アリスの債務を健全な水準に戻し、プロトコルの資金の安全性を確保する(プロトコルは清算を開始したユーザーに報酬を与える)。
清算はこの攻撃の焦点ではありませんが、攻撃プロセスに関与していました。 ここでは、任意のユーザーがある種類のトークンを使って他者の債務を清算でき、それによって対応するhTokenが減少するという点だけ理解しておけば十分です。
脆弱性
精度低下の問題
ハッカーは、redeem() を通じて担保を引き出す際、差し引かれるべきhTokenの計算結果が 1.99999992(2に非常に近いが2未満)になるように仕向けます。truncate() 関数内で整数に変換する際、切り捨て処理が行われるため、最終的な結果は1となります。

exchangeRate
前述のように exchangeRate の計算には getCash() が含まれており、これはhTokenコントラクトが保有する基礎資産の残高を指します。基礎資産トークンをコントラクトに直接送金する(mint を使わず、単に送金する)ことで、ハッカーは exchangeRate を操作することができます。
ただし、この exchangeRate の問題単体ではプロトコルのセキュリティを侵害することはできず、ハッカーだけで利益を得ることはできません。 今回の攻撃の文脈では、主にハッカーの利益を増幅させ、プールを急速に枯渇させるために悪用されました。そうでなければ、攻撃は一撃必殺ではなく、甚大な影響を与えるために何度も反復が必要な「小さな突き」の繰り返しになってしまいます。
要約すると、精度低下こそが本攻撃の核心的な問題です。
攻撃プロセス
以下に攻撃のトランザクションを示します。Phalcon Explorerを使用して、この複雑なトランザクションを分析します。
トランザクション: 0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451
-
Aave V3からフラッシュローンを通じて500 WBTCを借り入れる。
-
以前に取得したすべてのhWBTCを
Redeemし、hWBTCのtotalSupplyを0にリセットする。
この前の目的は、フラッシュローンを使用して準備資金を確保し、hWBTCを新しいマーケットのようにリセットすることにあります。
-
2つ目の攻撃コントラクト(以下、攻撃コントラクト2)を作成し、すべてのWBTC(500.30063816 WBTC)を攻撃コントラクト2に送金する。

-
4 WBTCを使用してhWBTCを
Mint()し、200 hWBTCを生成する。 -
199.99999998 hWBTCを
Redeem()し、hWBTCの合計を0.00000002(2 wei hWBTC)にする。 -
すべてのWBTC(500.30063816 WBTC)をhWBTCに送金する。直接送金してもhWBTCは増加しない点に注意。これはプールへのWBTCの寄付と見なすことができます。このステップの主な目的は、前述の
exchangeRateを操作することです。この時点でhWBTCのtotalSupplyは2 wei hWBTCのままですが、プール内には500.30064194 WBTCが存在するため、exchangeRateが元の数百倍になります。

-
hETHマーケットから1021 Etherを借り入れる。
-
50030063815 WBTCを
Redeem()する際、計算上は1.9999992 hBTCが差し引かれるはずですが、精度低下により1 hBTCしか差し引かれず、大幅な精度低下(約50%)が発生します。
この時点で、ハッカーは500 WBTC + 1021 Etherを保持しており、1021 Etherの利益を得ることに成功しました。 -
攻撃者は残りのhWBTCを
liquidate()し、totalSupplyを0にリセットして、他の市場への攻撃を開始する準備をします。 hWBTC内のほとんどのWBTCは引き出されているため、ハッカーはわずか0.000002 Etherでこれを行います。
-
他の市場を攻撃し続け、プロトコル全体を枯渇させる。
-
Aaveへのフラッシュローンを返済する。
セキュリティ上の推奨事項
レンディングプロトコルへの緩和策
この問題は、特にCompoundやAaveのフォークにおいて一般的です。プロアクティブなアプローチとしては、新しいマーケットを立ち上げる際に、totalSupply が決して0にならないように、少量の会計トークンをミントしておくことが有効です。
精度低下の問題への緩和策
精度低下に起因する一連の問題を回避するために、実務上の有効な手法として 最小値を設定すること が挙げられます。この戦略は、非常に小さな値を扱う際の精度低下によって引き起こされる深刻な影響を回避するのに役立ちます。
本連載の他の記事を読む:
- 導入:2023年の「衝撃的」なセキュリティインシデント トップ10
- #1: Flashbotsリレーの脆弱性を悪用したMEVボットの収穫
- #2: Euler Financeインシデント:2023年最大のハッキング
- #3: KyberSwapインシデント:非常に巧妙な計算を用いた丸めエラーの裏をかく悪用
- #4: Curveインシデント:コンパイラのバグが生成した異常なバイトコード
- #5: Platypus Finance:幸運にも3度の攻撃を生き延びた
- #7: ParaSpaceインシデント:業界で最も致命的な攻撃を阻止するための時間との戦い
- #8: SushiSwapインシデント:不器用な救出劇が招いた模倣攻撃の連鎖
- #9: MEV Bot 0xd61492:巧妙なエクスプロイトによって捕食者から獲物へ
- #10: ThirdWebインシデント:信頼されたモジュール間の非互換性が露呈させた脆弱性



