
Yearn Finance 攻撃事件の分析
TechFlow厳選深潮セレクト

Yearn Finance 攻撃事件の分析
本稿では、Yearn Financeの攻撃事件における攻撃の流れと、脆弱性が生じた原因について分析する。
概要
2023年4月13日,Yearn Financeがハッキングされ、約1000万ドルの損失が発生しました。本稿では、攻撃のプロセスと脆弱性の原因を分析します。
攻撃分析
以下は攻撃取引の例です:
https://etherscan.io/tx/0xd55e43c1602b28d4fd4667ee445d570c8f298f5401cf04e62ec329759ecda95d
攻撃者はBalancerからフラッシュローンを発行し、500万DAI、500万USDC、および200万USDTを借りました:

その後、Curve上で、攻撃者は500万DAIを695,000 USDTに交換し、350万USDCを151 USDTに交換しました:

攻撃者はIEarnAPRWithPoolのrecommend関数を呼び出して現在のAPRをチェックしました。この時点で、AaveのAPRのみが0でない値を示していました:

次に、攻撃者は800,000 USDTを攻撃用スマートコントラクト(アドレス:0x9fcc1409b56cf235d9cdbbb86b6ad5089fa0eb0f)に転送しました。このコントラクト内で、攻撃者はAave:Lending Pool V1のrepay関数を複数回呼び出し、他人の債務を返済することでAaveのAPRを0に設定しました:

攻撃者はyUSDTのdeposit関数を呼び出し、900,000 USDTを担保に入れて820,000 yUSDTを取得しました:

次に、攻撃者はbZx iUSDCのmint関数を呼び出し、156,000 USDCを使用して152,000 bZx iUSDCを発行し、それをYearnのyUSDTに転送しました:

攻撃者はYearn:yUSDTのwithdraw関数を呼び出し、820,000 yUSDTを1,030,000 USDTに交換しました。この時点で、コントラクト内には攻撃者が転送したbZx iUSDCのみが残っていました:

次に、攻撃者はYearn:yUSDTのrebalance関数を呼び出し、bZx iUSDCをバーン(burn)しました:

その後、攻撃者はyUSDTコントラクトに1/e6のUSDTを転送し、deposit関数を呼び出して10,000 USDTを担保に入れ、1,252,660,242,850,000 yUSDTを取得しました:

その後、Curve上で攻撃者は70,000 yUSDTを5,990,000 yDAIに、4億yUSDTを4,490,000 yUSDCに、そして1,240,133,244,352,200 yUSDTを1,360,000 yTUSDに交換しました:

その後、yearn: yDAIおよびyearn: yUSDCそれぞれでwithdrawを呼び出し、678万DAIおよび562万USDCを引き出し、フラッシュローンを返済しました:

脆弱性分析
今回の攻撃で最も重要な点は、攻撃者がわずか10,000 USDTを預け入れて1,252,660,242,850,000個のyUSDTを取得できたことです。deposit関数の実装を見てみましょう:

shareの数量は変数poolに依存しており、poolが小さいほどshareの数量が大きくなります。ここでpoolの値は _calcPoolValueInToken 関数によって取得されます:

攻撃者はrebalance関数を呼び出した後、コントラクト内にはUSDCのみが存在していましたが、_balance()関数はUSDTの残高しか取得しないため、USDCの残高はカウントされず、結果としてpoolの値は1(攻撃者が転送したもの)となりました:



これは明らかにプロジェクト側の設定ミスです。yUSDTコントラクト内には本来USDT系のトークンのみが存在すべきですが、fulcrum変数にはUSDC関連のbZx iUSDCトークンが設定されており、そのためyUSDT内のUSDC残高は_balanceに含まれていませんでした:


なぜ攻撃者はrebalance関数を呼び出してbZx iUSDCトークンをバーンできたのでしょうか?rebalance関数の実装を見てみます:



_withdrawFulcrum()関数内にはredeemおよびburn操作が含まれており、「newProvider != provider」が成立する必要があります。ここでrecommend()関数の実装は以下の通りです:

攻撃者は IIEarnManager(apr).recommend(token) の戻り値を制御し、すべて0になるようにしてnewProviderを変更しました:

どのようにしてすべて0にしたのかというと、この関数の戻り値は各DeFiにおけるAPRの計算結果に依存しています。Compound、bZx、dydxにはプールが存在しないため、Aave(Aave: Lending Pool Core V1)のみを制御すれば十分でした:

戻り値を0にするには、apr.calculateInterestRates関数の最初の戻り値を0にする必要があります:

つまりcurrentLiquidityRateを0にする必要があります。この値は_totalBorrowsStableおよび_totalBorrowsVariableに依存しており、これら二つの値が0の場合、currentLiquidityRateも0になります:


_totalBorrowsVariableが0であるとは、Aave: Lending Pool Core V1に誰も借り入れがない状態を意味します。これを達成するために、攻撃者はプール内のすべてのユーザーの債務をrepayしました:

最終的に、攻撃者は_totalBorrowsVariableを0にし、それによりrebalance関数を呼び出してbZx iUSDCトークンをバーンできるようになりました:

まとめ
今回のYearn Financeへの攻撃事件の根本的な原因は、プロジェクト側のコントラクト設定ミスにあります。攻撃者は一連の巧妙な手順によりこの脆弱性を悪用し、最終的に約1000万ドルの利益を得ました。
TechFlow公式コミュニティへようこそ
Telegram購読グループ:https://t.me/TechFlowDaily
Twitter公式アカウント:https://x.com/TechFlowPost
Twitter英語アカウント:https://x.com/BlockFlow_News














