
SharkTeam:マルチキャストにおける任意アドレス偽装脆弱性の原理分析
TechFlow厳選深潮セレクト

SharkTeam:マルチキャストにおける任意アドレス偽装脆弱性の原理分析
今回の攻撃事件の根本原因は、ERC-2771 において[Forwarder]がmulticall専用に設計されていないことにある。
執筆:SharkTeam
2023年12月8日、OpenZeppelin公式がコミュニティに対して重要なセキュリティアラートを発表しました。このアラートでは、プロジェクトの統合においてERC-2771標準とマルチコール(Multicall)方式を使用する場合、任意のアドレス詐称攻撃のリスクが存在する可能性があると指摘しています。
SharkTeamはこの事象を直ちに技術的に分析し、セキュリティ対策をまとめました。今後のプロジェクトが教訓とし、共にブロックチェーン業界のセキュリティ体制を強化することを願っています。
一、攻撃トランザクションの分析
この脆弱性に関連する一連の攻撃トランザクションが存在するため、その中から一つの攻撃トランザクションを取り上げて分析を行います。
攻撃者アドレス:
0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A
攻撃トランザクション:
0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
攻撃手順:
1. 最初に、攻撃者(0xFDe0d157)は5枚のWETHを使用して、約3,455,399,346枚のTIMEを交換しました。

2. その後、攻撃者(0xFDe0d157)は悪意のあるcalldataパラメータを構築し、[Forwarder].execute関数を呼び出しました。
3. [Forwarder].execute関数を呼び出す際、悪意のあるcalldataによりTIMEコントラクトのmulticall関数がトリガーされました。その後、残りのcalldataを使ってTIMEコントラクトのburn関数が実行され、プール内のTIMEトークンが破壊されました。

二、脆弱性の分析
まず、今回の攻撃は主に以下の要素に関係しています:ERC2771、Multicall、そして巧みに構築されたcalldataです。TIMEトークンコントラクトの継承関係を確認できます:

1. ERC2771は仮想的なmsg.senderを持つ機能を提供し、ユーザーが第三者[Forwarder]にトランザクションの実行を委任できるようにすることで、ガスコストを削減します。トランザクション送信時に、msg.senderアドレスがcalldataに追加されます。
2. TIMEトークンコントラクトはERC2771Contextを継承しています。[Forwarder]がコントラクトを呼び出すとき、_msgSender()はcalldataをチェックし、右シフトして末尾の20バイトを期待されるmsg.senderとして切り取ります。

3. Multicallは、単一の関数呼び出しを同じコントラクト内で複数の関数を順番に呼び出す形式に変える方法です。ユーザーがエンコードした呼び出しの配列を受け取り、自身のコントラクト上で実行します。この関数は呼び出し配列を走査し、各操作に対してdelegatecall()を実行します。これにより、ユーザーは独自の操作セットを組み合わせ、プロトコルで事前に定義されていない操作でも、同一トランザクション内で順次実行できます。主な目的はガス節約です。

4. 巧みに構築されたcalldataに関して、攻撃者は[Forwarder].execute関数を呼び出し、関連するパラメータを渡しました。

data値を読みやすい形式に整形すると、次のようになります:

攻撃者(0xFDe0d157)は現在のcalldataに対するオフセット操作により新しいdata値を取得し、それをmulticall(bytes[])関数に渡しました。新しいdataの最初の4バイトはburn(uint256)関数のセレクタであり、amountパラメータは62227259510000000000000000000です。
5. multicall(bytes[])関数内では、delegatecallによってburn(uint256)関数が呼び出されます。0x20の行にある0x760dc1e043d99394a10605b2fa08f123d60faf84アドレスは、calldataの末尾に最初に追加されていたものです。このアドレスはUniswapv2上のTIME-ETH流動性プールに対応しており、前述の「期待されるmsg.sender」です。

6. 上記のmsg.senderがなぜTIME-ETH流動性プールのアドレスになったのか?理由は、当初のmsg.senderは[Forwarder]コントラクトのアドレスでした。信頼できる[Forwarder]かどうかを判断するために、信頼できる[Forwarder]であれば、msg.senderをcalldataの末尾20バイトに設定する仕組みになっているためです。
三、セキュリティ推奨事項
今回の攻撃の根本原因は、ERC-2771において、[Forwarder]がマルチコール専用に設計されていない点にあります。攻撃者は_msgSender()関数内の関連パラメータをマルチコールの外部呼び出しに追加し、今回の事例では[Forwarder].execute関数を通じて実行しました。multicall関数内で、一部の関数も_msgSender()の関連パラメータを付加するため、攻撃者は_msgSender()を騙すことが可能になります。結果として、攻撃者はマルチコールを使って関連関数を呼び出し、任意のアドレスを模倣することが可能となり、最終的にはプール内のTIMEトークンを破壊する権限を得ることになりました。
この事件に対して、以下の緩和および防止策が取れます:
1. バグ修正済みの新バージョンを使用する。OpenZeppelinの新バージョンのMulticallには、ERC2771contextデータのcontextサフィックス長が含まれており、ERC-2771が期待するcontextサフィックス長を識別できます。そのため、信頼できる[Forwarder]からの呼び出しは、各サブ関数呼び出しに対して正しく認識・適応されます。

以下は、バグありバージョンと更新済みバージョンの比較図です:

2. コントラクトによるmulticall呼び出しを禁止し、[Forwarder]の使用を防ぐ。ThirdWebを例に挙げると、この方法はOpenZeppelinの解決策とは異なり、OpenZeppelinは依然としてコントラクトによるmulticallを許可しています。以下はThirdWebのバグありバージョンと更新済みバージョンの比較図です。

【免責事項】市場にはリスクがあります。投資は慎重に行ってください。本記事は投資助言を構成するものではありません。読者は本文に示される意見、見解、結論が自身の状況に適合しているか検討する必要があります。これに基づく投資行動の責任はすべて読者自身に帰属します。
TechFlow公式コミュニティへようこそ
Telegram購読グループ:https://t.me/TechFlowDaily
Twitter公式アカウント:https://x.com/TechFlowPost
Twitter英語アカウント:https://x.com/BlockFlow_News










