百万ドルの火線排雷:DeFi資産の権限脆弱性を深く解読

アンバーグループ
2021-04-30 14:50:16
コレクション
あなたのウォレットアドレスは他の人があなたの資産を使用することを許可していますか?

この記事はAmber Groupからのもので、著者は呉家志です。原文のタイトルは「Exploiting Primitive Finance Approval Flaws」です。

イベント概要:2月24日、Primitive Finance(イーサリアムチェーン上のデリバティブプロトコル)に関する脆弱性分析レポートが業界内で注目を集めました。このレポートでは、3件のホワイトハット攻撃(セキュリティ脆弱性の調査を目的としたハッカー攻撃)とその脆弱性の原理が説明されています。1ヶ月以上後の4月14日、Amber Groupのブロックチェーンセキュリティ専門家である呉家志博士を代表とするチームは、あるウォレットアドレスに100万ドル以上の資産(500 WETH)がリスクにさらされていることを発見しました。ローカルで攻撃を再現した後、彼のチームはImmunefi(DeFi脆弱性報奨プラットフォーム)を通じてPrimitiveプロジェクトチームに連絡し、潜在的な被害者がWETHの承認をリセットするのを成功裏に支援し、危機を解除しました。この記事では、チームがどのようにシミュレーション環境でこの脆弱性を利用し、ブロックチェーンデータ分析を通じて潜在的な被害者のウォレットアドレスを見つけたかを紹介します。

原理:スマートコントラクトの隙間

現在のEVM(イーサリアム仮想マシン)およびERC-20(イーサリアムスマートコントラクトのプロトコル標準)の構造において、ユーザーがスマートコントラクトと相互作用する際、スマートコントラクト自体にはERC-20の転送イベントをコードレベルでキャッチするコールバックメカニズムが欠けています。例えば、アリスがボブに100個のXYZトークンを送ると、ボブのXYZ残高はXYZコントラクト内で更新されます。しかし、ボブはどのようにして自分のXYZが増えたことを知るのでしょうか?彼はEtherscan(イーサリアムエクスプローラー)をチェックするか、または彼のウォレットアプリがイーサリアムノードから自動的に最新の残高を取得します。アリスが100XYZをスマートコントラクトのチャーリーに送った場合、チャーリーはどのようにして自分のXYZ残高が増えたことを知るのでしょうか?

image

実際、チャーリーは100XYZを受け取った瞬間に自分の最新の残高を取得することはできません。理由は、この転送がXYZコントラクト上で発生しており、チャーリーのコントラクトではないからです。スマートコントラクトがデプロイされた後は、オペレーティングシステムのように、特定の場所にコードが置かれ、呼び出されるまで機能しません。この問題を解決するために、ERC-20標準には広く使用されているメカニズムが存在します---approve()/transferFrom()。

image

例えば、アリスがチャーリーに100個のXYZトークンを預ける必要がある場合、アリスは事前にチャーリーに彼女の100XYZの使用を許可することができます。この時、チャーリーのdeposit()関数は、1つのトランザクション内でtransferFrom()を通じてアリスのウォレットから100XYZを引き出し、チャーリーコントラクトの状態(例えば、アリスのXYZ預金残高cXYZを増やす)を更新できます。摩擦を減らすために、多くのDAppはユーザーにプロジェクトアドレスに無制限のXYZの使用を許可させることさえあります。これにより、後続のtransferFrom()呼び出しが直接成功し、何度も許可をクリックする手間や手数料を省くことができ、チャーリーをホワイトリストに追加することと同じです。この方法にはリスクが残ります。もしチャーリーが悪用したり攻撃を受けたりした場合、アリスの資産が危険にさらされることになります。

2020年6月18日に発生したこの事故は、制御されたり問題のあるスマートコントラクトがどのように利用され、資産損失を引き起こすかを証明しました。以下のコードに示すように、safeTransferFrom()は「safe」と名付けられたtransferFromですが、意図せず公開関数として宣言されてしまい、誰でもBancorコントラクトの身分を使って任意のユーザー(from)の任意の数量(value)の任意の資産(token)を任意のアドレス(to)に転送できるようになりました。

image

簡単に言えば、もしアリスがBancorを使用し、Bancorに無制限のDAIの使用を許可していた場合、彼女のウォレットにDAIの残高がゼロより大きくなると、ハッカーはすぐに彼女のDAIを転送することができるのです。

診断:ハッカーはどのように「セキュリティチェック」を回避したのか?

上記の脆弱性分析レポートによると、この外部関数には類似の脆弱性がありますが、Bancorの脆弱性のように直接利用することはできません。実際、攻撃者は2つのERC20トークンコントラクト、1つのUniswap資金プールを偽造し、下図に示すmsg.sender == address(this)チェックを回避するためにUniswapのフラッシュローンを開始する必要があります。複雑に聞こえますが、経験豊富なハッカーにとってはそれほど難しくありません。

image

PrimitiveはなぜflashMintShortOptionsThenSwap()のようなインターフェースを実装する必要があるのでしょうか?実際には特定の使用シーンがあり、openFlashLong()関数で見ることができます。flashMintShortOptionsThenSwap()はUniswapのフラッシュスワップ呼び出しパラメータにラップされており、1371行目でフラッシュスワップがトリガーされた後、コールバック関数UniswapV2Call()が呼び出されます。この時、UniswapV2Call()がPrimitiveコントラクト内にあるため、上記のmsg.sender == address(this)チェックを通過できます。

image

注意すべきは、openFlashLong()関数の1360行目にmsg.senderが書かれており、通常の状況ではPrimitiveは呼び出し元の資金のみを使用できることを示しています。しかし、攻撃者は偽造したペアとparamsを使用して、1371行目のようにPrimitiveコントラクトのUniswapV2Call()を直接呼び出し、flashMintShortOptionsThenSwap()のチェックを回避することができます。この場合、paramsは完全に制御可能であり、1360行目のmsg.senderは任意の過去にPrimitiveに許可されたウォレットアドレスに置き換えることができ、その後flashMintShortOptionsThenSwap()内のtransferFrom()呼び出しを通じて資産を盗むことができます。

image

追跡:潜在的な被害者を特定する

もしハッカーが偶然にある「大口」が問題のあるコントラクトに許可を与えていることを知っていれば、彼はこの脆弱性を利用して被害者から大量の資金を盗むことができます。しかし、これはブロックエクスプローラーを使用するだけでは非常に難しいことです。特にコントラクトが長期間デプロイされており、多くのユーザーがいる場合はなおさらです。分析する必要があるデータは、手動でEtherscanを検索しても得られるものではありません。

Google Cloud Public Datasets(GoogleがBigQueryでホストしているデータセット)は、この時に役立ちます。成功したapprove()呼び出しごとに、イーサリアム上でApproval()イベントが発生するため、BigQuery(Googleのクラウドデータウェアハウスソリューションで「ビッグデータ」レポートを処理するためのもの)サービスを通じてすべてのイベントを特定し、興味のある部分をフィルタリングすることができます。例えば、_spenderがPrimitiveコントラクトであるすべてのイベントです。

image

以下は、GCP上で潜在的な被害者を特定するために実際に使用したSQL文です。5行目には、検索対象のイーサリアムデータベースと記録イベントのテーブルを限定していることが見えます。7行目ではApproval()イベントをフィルタリングし、8行目では特定の_spenderをフィルタリングしています。また、6行目ではブロック高の範囲をPrimitiveコントラクトがデプロイされた後に設定しており、これによりBigQueryがスキャンするデータ量を大幅に減少させます。このようなSQLの最適化は、GCPの請求書に直接反映されます。

image

次に、approve(_spender, 0)で権限をリセットしたアカウントをリストから除外することで、SQLクエリをさらに最適化し、最終的なアカウントリストを得ることができます。最終的なリストを得たら、これらのアカウントを監視するスクリプトを利用し、危険なアカウントが大量の資産を受け取った際に警告を発することができます。これは、重大な損失を引き起こす可能性が高いからです。

ある水曜日の朝、ロボットが警告を発しました。ある潜在的な被害者が北京時間4月13日午前5時24分に約500 WETHの資産を受け取ったことが確認され、価値は100万ドルを超えました。公開された3件のホワイトハット攻撃と比較して、この被害者が攻撃を受けた場合、失われる金額は早期の3件の合計を上回ることになります。

image

私たちは北京時間9:32にPrimitiveプロジェクトの脆弱性報奨プログラム運営者Immunefiに緊急連絡を取り、どのように(再)この脆弱性を利用してシミュレーション環境で被害者の500 WETHを盗むかを示し、以下のスクリーンショットなどの証拠を提供しました。

image

Primitiveチームの助けを借りて、潜在的な被害者は10:03にWETHの承認をリセットし、危機を解除しました。

image

2日後、Primitiveチームはこの発見に対して脆弱性報奨を授与し、公開で感謝の意を表しました。この報奨金は、発表前にCryptoRelief(インドの新型コロナウイルス感染症の支援に取り組む救済基金)に寄付されました。

再現:脆弱性の利用を分解する

脆弱性を利用する第一歩として、2つのERC20コントラクト:RedeemとOptionを準備する必要があります。

image

その中で、Redeemコントラクトは標準的なERC20であり、OpenZeppelinの実装に基づいてmint()インターフェースを公開するだけで、トークンの数量を制御できるようにします。以下のようになります:

image

Optionコントラクトは相対的に複雑であり、以下のコードスニペットからわかるように、いくつかのグローバル変数(例えば、redeemToken)や公開関数(例えば、getBaseValue())を意図的に構築する必要があります。これらはPrimitiveのビジネスロジックで使用されます。さらに、Optionコントラクトを初期化するために3つのパラメータを渡す必要があります:

· redeemToken:先ほど構築したRedeemコントラクトのアドレス

· underlyingToken:攻撃対象アカウントが保有する資産コントラクトのアドレス

· beneficiary:受益者アドレス、つまり攻撃成功後に被害者の資産を移転する対象アドレス

image

ここで特に説明が必要なのは、mintOptions()という関数です。上記のコードからわかるように、これはすべてのunderlyingTokenをbeneficiaryアドレスに直接送信します。これは、内部関数mintOptionWithUnderlyingBalance()がflashMintShortOptionsThenSwap()の際にunderlyingTokenをOptionトークンコントラクトに送信し、mintOptions()を通じてOptionトークンを発行するためです。したがって、偽造されたOptionコントラクト内では、mintOptions()を引き出し呼び出しとして直接使用し、underlyingTokenをbeneficiary(つまり攻撃を仕掛けるアドレス)に送信し、後でフラッシュローンの資金を返済するために使用します。

image

次に、作成したRedeemおよびOptionトークンを使用してUniswapの流動性プールを作成します。このプールのアドレスは、被害者のウォレットから転送された資金を受け取るために使用されます。実際、各Uniswapプールには等価の2種類の資産が存在します。例えば、WETHとRedeem(つまりOption.redeemToken())です。脆弱性を利用するためには、プールに流動性を注入する必要があります。Redeemは自分たちが作成したもので、無限のトークンを鋳造できますが、WETHはどうでしょうか?

image

フラッシュローンの助けを借りて、基本的に無限の資金を利用してさまざまなことを行うことができます。資金を1つのトランザクション内で返済できることを確認する限りです。このケースでは、Aave V2のフラッシュローンを使用して、被害者の総資産の99.7%に相当する資金を上述の流動性プールに預けました。

image

Aaveの設計により、ローン資金を受け取った後の操作を実行するためにexecuteOperation()というコールバック関数を実装する必要があります(例えば、Lib.trigger()を呼び出すなど)し、最後にapprove()を通じてAaveコントラクトにフラッシュローンの資産と手数料を引き取る権限を与えます。

image

まとめ

EVMに基づくスマートコントラクトの世界では、approve()/transferFrom()は長年存在する固有の問題です。DeFiユーザーにとっては、自分のウォレットアドレスが他の人に資産の使用を許可しているかどうかに注意を払い、定期的に資産の使用権をリセットする必要があります。プロジェクトチームにとっては、ローンチ前にさまざまな角度からテストし、コードを攻撃するためにもっと時間と労力をかける必要があります。なぜなら、あなたがプログラミングしているのは、すべてのユーザーの真金白銀だからです。

著者について

呉家志は、世界的に先進的な暗号金融インテリジェンスサービスプロバイダーであるAmber Groupに雇われており、ブロックチェーンセキュリティ専門家として活動しています。彼はアメリカのノースカロライナ州立大学でコンピュータサイエンスを専攻し、博士号を取得しました。彼はAndroidセキュリティ分野のリーダーである蒋旭宪教授の指導を受け、アメリカでの学業期間中にシステムセキュリティの研究に従事し、主に仮想化セキュリティとAndroidシステムセキュリティに焦点を当ててきました。呉家志博士は、世界のAndroidセキュリティ分野で大きな影響力を持ち、多くの科学論文を発表しており、Androidシステムの脆弱性セキュリティに関して豊富な経験を持っています。彼は2017年にブロックチェーンセキュリティ分野に転身し、世界初の分散型匿名バグバウンティプラットフォームDVP(Decentralized Vulnerability Platform)の責任者を務め、全ネットワークのホワイトハットハッカーに対してオープンソースの基盤コードの脆弱性を探すよう呼びかけました。

関連タグ
ChainCatcherは、広大な読者の皆様に対し、ブロックチェーンを理性的に見るよう呼びかけ、リスク意識を向上させ、各種仮想トークンの発行や投機に注意することを提唱します。当サイト内の全てのコンテンツは市場情報や関係者の見解であり、何らかの投資助言として扱われるものではありません。万が一不適切な内容が含まれていた場合は「通報」することができます。私たちは迅速に対処いたします。
チェーンキャッチャー イノベーターとともにWeb3の世界を構築する