慢雾分析Creamが1.3億ドル盗まれた経緯:貸出プールの欠陥を利用し、悪意のある価格操作
作者:Kong,慢雾安全团队
慢雾の情報によると、2021年10月27日、Cream Financeが再び攻撃を受け、約1.3億ドルの損失が発生しました。慢雾安全チームは直ちに分析に介入し、簡単な分析を以下に共有します。
攻撃の核心
今回の攻撃の核心はCreamの貸出プールにおける担保価格取得の欠陥を利用し、悪意を持って担保価格を引き上げることで、攻撃者がCreamの貸出プールからより多くのトークンを借り出すことができるようにしたことです。
攻撃の詳細
まず、攻撃者はDssFlashから5億DAIをフラッシュローンで借り、その後借りた5億DAIをyearnのyDAIプールに担保として預け、約4.5億yDAIの証明書を取得しました。
その後、攻撃者は取得したyDAIトークンをCurveのyDAI/yUSDC/yUSDT/yTUSDプールで単一トークン流動性追加を行い、相応の流動性証明書を得ました。続いて、攻撃者は得た証明書をyvWBTCプールに担保として預け、yUSD証明書を取得し、後のCream crYUSD貸出プールへの担保準備を行いました。
その後、攻撃者はCreamのcrYUSD貸出プールにyUSD証明書を担保として預け、担保規模を拡大するために、攻撃者はAAVEから約52.4万WETHをフラッシュローンで借り、これをCreamのcrETHプールに担保として預けました。
攻撃者はcrETHプールに大量のETHを担保として預けることで、crYUSDプールのyUSDを全て借り出し、再度crYUSDプールに担保として預けるための十分な借入能力を得ました。その後、攻撃者はcrYUSDプールでの循環貸出を行い、レバレッジの形で自身のcrYUSDプールにおけるyUSDの担保規模を拡大し、後の価格操作による利益を得る準備をしました。
その後、攻撃者はyDAI/yUSDC/yUSDT/yTUSD 4Pool証明書を取得して価格を操作するために、約1,873 ETHを使ってUniswap V3から約745万USDCを交換し、Curve 3Poolを通じて約338万DUSDトークンに交換しました。
次に、攻撃者は取得したDUSDトークンを使ってYVaultPeakからyDAI/yUSDC/yUSDT/yTUSD 4Pool証明書を引き出し、この証明書を利用してyUSD(yvWBTC)プールからyDAI/yUSDC/yUSDT/yTUSDトークンを引き出しました。
その後、攻撃者は今回の攻撃の重要な操作を開始し、約843万のyDAI/yUSDC/yUSDT/yTUSDトークンを直接yUSDプールに転送しました。これは通常の担保操作を通じて担保されていないため、843万のyDAI/yUSDC/yUSDT/yTUSDトークンは個別に記帳されず、直接yDAI/yUSDC/yUSDT/yTUSD証明書の保有者に分配され、結果としてそのシェアの価格を引き上げることになりました。
crTokenでは、担保価格が悪意を持って引き上げられたため、攻撃者が担保した大量のyUSDは、より多くの資金を借り出すことを可能にしました。最終的に、攻撃者はCreamの他の15のプールをすべて借り空にしました。次に、CreamのcrToken貸出プールにおける具体的な貸出ロジックを追跡します。
cTokenコントラクトから、主な貸出チェックがborrowAllowed関数にあることがわかります:
borrowAllowed関数を追跡すると、427行目で、getHypotheticalAccountLiquidityInternal関数に基づいて、リアルタイムの状態でそのアカウントに対応するすべてのcTokenの資産価値の合計と借入の資産価値の合計を確認し、cTokenの資産価値と借入のトークン価値の合計を比較することで、ユーザーが引き続き借入できるかどうかを判断します。
getHypotheticalAccountLiquidityInternal関数を追跡すると、担保の価値取得が886行目のoracle.getUnderlyingPriceから来ていることがわかります。
オラクルのgetUnderlyingPrice関数を追跡すると、トークン150行目のgetYvTokenPrice関数を通じて価格を取得することが容易にわかります。
getYvTokenPrice関数をさらに追跡すると、yvTokenInfo.versionがV2であるため、yVaultのpricePerShare関数を通じて価格を取得します。
pricePerShareを追跡すると、直接shareValueを価格として返し、shareValueはtotalAssetsをコントラクトの総シェア数(self.totalSupply)で割って単一シェアの価格を計算しています。したがって、攻撃者はtotalAssetsを操作して引き上げることで、単一シェアの価格を上昇させ、攻撃者の担保価値を高めてより多くの他のトークンを借り出すことができます。
totalAssetsがどのように取得されるかを確認すると、772行目から、totalAssetsは現在のコントラクトのyDAI/yUSDC/yUSDT/yTUSDトークンの数量と、戦略プールに担保されている資産の額を加算して得られることが明確にわかります。したがって、攻撃者はyUSDコントラクトにyDAI/yUSDC/yUSDT/yTUSDトークンを直接転入することで、シェア価格を引き上げ、利益を得ることができます。
Ethx.infoを通じて、pricePerShareの前後の変化を明確に見ることができます:
最終的に、攻撃者は他のプールを借り空にした後、フラッシュローンを返済し、利益を得て退場しました。
まとめ
今回の攻撃は典型的なフラッシュローンを利用した価格操作です。 Creamの貸出プールはyUSDプールのシェア価格を取得する際に直接pricePerShareインターフェースを使用しており、このインターフェースはコントラクトの担保残高と戦略プールの担保資産額を加算して総シェア数で割って単一シェアの価格を計算しています。したがって、ユーザーがyUSDに担保を直接転入することで、単一シェアの価格を簡単に引き上げ、最終的にCreamの貸出プールにおける担保をより多くの資金を借り出すことができます。
附:前回のCream Financeのハッキング分析の振り返り