2023年12月5日、著名なWeb3開発プラットフォームであるThirdwebは、プリビルドコントラクトに影響を与える重大なスマートコントラクトのセキュリティ脆弱性を開示しました。この致命的な欠陥は、これらの特定の脆弱なコントラクトを使用してデプロイされたすべてのERC-20、ERC-721、およびERC-1155トークンに影響を与えました。開示後の数日間、これらの脆弱なコントラクトでデプロイされたトークンは、一連の攻撃で徐々に悪用され、根本的な非互換性の深刻さが浮き彫りになりました。
ThirdWebスマートコントラクトの脆弱性の理解
ThirdWebインシデントの根本原因は、スマートコントラクト開発の2つの基本的なコンポーネントであるERC-2771とOpenZeppelinのMulticall実装の予期せぬ相互作用にあります。脆弱性を完全に理解するには、各コンポーネントを個別に、そしてそれらの相互作用がどのように悪用可能な経路を作成したかを理解することが不可欠です。
ERC-2771: メタトランザクションと信頼できるフォワーダー
EIP-2771は、Recipientコントラクトが信頼できるForwarderコントラクトを介してmeta-transactionsを受け入れることを可能にする、コントラクトレベルのプロトコルを定義しています。この標準は、サードパーティ(フォワーダー)がユーザーに代わってガス料金を支払うことを可能にすることで、ユーザーエクスペリエンスを向上させるために不可欠であり、ユーザーがネイティブブロックチェーントークンを保持する必要性を抽象化します。
実際には、OpenZeppelinのERC2771Contextは広く採用されている実装です。その中核機能は、信頼できるフォワーダーからのcalldataの最後の20バイトを、効果的な_msgSender()として扱うことを含みます。このライブラリを使用する開発者にとって、一般的な慣行は、メタトランザクションとの互換性を確保するために、msg.senderのすべての直接的な使用を_msgSender()に置き換えることです。同様に、_msgData()は、追加された送信者情報を含まない元のトランザクションデータを取得するために使用されます。
function _msgSender() internal view virtual override returns (address) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return msg.data[:calldataLength - contextSuffixLength];
} else {
return super._msgData();
}
}
Multicall: 効率のためのトランザクションのバッチ処理
Multicall機能により、ユーザーは複数の関数呼び出しを1つのトランザクションにバンドルすることができ、ガス費用を大幅に削減し、トランザクションの効率を向上させます。OpenZeppelinのMulticallUpgradeableは、この目的のために人気のある実装です。これは、calldataバイトの配列を受け取り、各エントリに対してdelegatecallを実行し、呼び出しコントラクトのコンテキスト内でそれらを実行します。
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = _functionDelegateCall(address(this), data[i]);
}
return results;
}
(注:ここで議論されているバグは、OpenZeppelinのMulticallの後のバージョンで修正されました。)
非互換性: ERC-2771とMulticallの競合
ThirdWebインシデントのスマートコントラクト脆弱性の核心は、ERC-2771とMulticallによるcalldataの処理方法における致命的な不整合から生じました。ERC-2771は、信頼できるフォワーダーがメッセージデータと送信者情報を一緒にパックすることを期待しています。その後、受信者コントラクトは、_msgData()と_msgSender()を使用して、この情報を正しくアンパックします。
しかし、脆弱な実装におけるMulticall関数は、ERC-2771がメタトランザクション用にデータをパックする方法と互換性があるように設計されていませんでした。具体的には、Multicallが呼び出しのバッチを処理する際、最初のメタトランザクションのために_msgSender()を正しく抽出してから、各個別の呼び出しのcalldataにこの送信者情報を追加してから実行するべきでした。この重要なステップが欠落していました。
Multicallによって処理される各サブコールに送信者情報が正しく追加されなかったため、ターゲットコントラクト内のERC-2771コンテキストは、サブコールの_msgData()の最後の20バイトから送信者情報をアンパックしようとしました。特に、攻撃者はこの最後の20バイトを制御できました。これにより、悪意のあるアクターは、Multicallによって処理され、次にERC-2771対応コントラクトによって解釈されたときに、操作された_msgSender()値(例:攻撃者が制御するアドレス、またはプロトコル自身のプールアドレス)で任意のロジックを実行する特定のcalldataを作成することができました。これにより、意図されたセキュリティチェックが事実上バイパスされ、両方の仕様で設定された期待が violated され、不正なアクションにつながりました。
ThirdWebインシデント: 攻撃分析と悪用
BlockSecのPhalconプラットフォームによって分析された攻撃トランザクションを使用して、ThirdWebインシデントのスマートコントラクト脆弱性悪用の実際の例を見てみましょう。
攻撃者の戦略は、_msgSender()を操作してUniswapプールを偽装し、そのトークン残高を吸い上げることでした。
-
ステップ1: 初期トークン取得。 攻撃者は、分散型取引所で5 WETHを3,455,399,346 TIMEトークンと交換することから始めました。これにより、後続の操作に必要なトークンが提供されました。
-
ステップ2: 悪意のあるMulticall実行。 これはエクスプロイトの核心です。攻撃者は、ERC-2771/Multicallの非互換性を悪用するように細工されたcalldataで信頼できるフォワーダーを呼び出しました。このcalldataが
Multicall関数によって解析されたとき、TIMEトークンコントラクトのburn関数が呼び出されました。致命的に、脆弱性により、_msgSender()はUniswapプールアドレスとして誤って解釈されました。これにより、攻撃者は実際の承認なしにUniswapプールが保有するTIMEトークンの大部分を事実上燃焼させることができました。BlockSec Phalconプラットフォームは、このフローを視覚化するための詳細なトランザクショントレースを提供します。
悪意のあるマルチコールを呼び出す攻撃者のトランザクショントレースを示す 上記の画像は、攻撃者の
Forwarder.execute呼び出しがどのように処理されるかを示しています。multicall関数はバイトの配列を受け取り、それが操作された_msgSender()でburn関数が呼び出されることにつながります。
マルチコール解析とバーン関数呼び出しの詳細ビュー Phalconからのこの詳細ビューは、コントラクトを呼び出すために使用される長さ1の
bytes[]を示しており、偽の_msgSender()の下でのburn関数の実行につながります。 -
ステップ3: 価格操作。 Uniswapプールから大量のTIMEトークンを燃焼させることにより、攻撃者はTIMEのプール流動性を劇的に削減しました。この人工的な希少性により、プール内のWETHに対するTIMEの価格が急騰しました。
-
ステップ4: 有利な裁定取引。 TIMEの価格が人為的にインフレしたため、攻撃者は残りの3,455,399,346 TIMEトークンを94 WETHと交換し、操作された価格から substantial な利益を実現しました。
この一連の出来事は、モジュールの非互換性に起因する微妙なスマートコントラクトの脆弱性を活用した洗練された攻撃を示しています。
BlockSecでスマートコントラクトを保護
隠された非互換性がプロジェクトをリスクにさらすことはありません。当社の専門監査人は、脆弱性が悪用される前に特定および軽減するために、包括的なスマートコントラクト監査を実施します。
Web3向けの最高のセキュリティ監査人
ローンチ前に設計、コード、およびビジネスロジックを検証
ThirdWebインシデントからの主な教訓と学び
ThirdWebインシデントは、特にサードパーティライブラリの相互作用に関するWeb3セキュリティに内在する複雑さを、重要なリマインダーとして提供します。
- 相互運用性のリスク: 急速に進化するDeFiスペースでは、プロジェクトはサードパーティライブラリやモジュールのスタックに大きく依存しています。これらのコンポーネントは開発を加速させますが、それらの相互作用は予期せぬ隠れた脆弱性を導入する可能性があります。ThirdWebインシデントは、OpenZeppelinの
ERC2771ContextやMulticallUpgradeableのような広く使用され、堅牢に見えるコンポーネントでさえ、それらの統合が慎重に処理されない場合、致命的なセキュリティギャップを作成する可能性があることを明確に示しています。 - 深い技術的監査が不可欠: この種のスマートコントラクトの脆弱性は、表面的チェックでは容易に検出されません。異なるモジュールがデータを処理および解釈する方法、特にcalldataを分析し、潜在的な不一致を特定するには、深い技術的専門知識が必要です。モジュール間の相互作用とエッジケースに焦点を当てた徹底的なスマートコントラクト監査が最重要です。
- 継続的な監視とインシデント対応: 強力な監査があっても、新しい攻撃ベクトルが出現する可能性があります。BlockSecのPhalconが提供するような継続的なブロックチェーンセキュリティ監視は、リアルタイムで不審なアクティビティを検出するために不可欠であり、損害を最小限に抑えるための迅速なインシデント対応を可能にします。
- 個々のモジュールセキュリティを超えて: 開発者は、個々のコンポーネントのセキュリティを超えて、スマートコントラクトシステム全体の包括的なセキュリティ体制を考慮する必要があります。異なるモジュール間でデータがどのように流れ、コンテキストがどのように保持または変更され、外部呼び出しがどのように処理されるかはすべて、重要な考慮事項です。
ThirdWebインシデントは、ブロックチェーンセキュリティに対する積極的で包括的なアプローチの重要性を強調しています。個々のライブラリの評判にのみ依存することは十分ではありません。それらの間の相互作用は厳密に精査される必要があります。
Phalconでオンチェーンインシデントを調査
BlockSecのPhalconは、リアルタイム監視、インシデント対応、および詳細なトランザクション分析のための主要なWeb3セキュリティプラットフォームです。ThirdWebインシデントのような複雑なエクスプロイトを比類のない明瞭さで理解します。
このシリーズの他の記事を読む:
- リードイン: 2023年のトップ10「素晴らしい」セキュリティインシデント
- #1: Flashbotsリレーの脆弱性を悪用したMEVボットの収穫
- #2: Euler Financeインシデント: 2023年最大のハッキング
- #3: KyberSwapインシデント: 極めて微妙な計算による丸め誤差の巧妙な悪用
- #4: Curveインシデント: コンパイラエラーが親切なソースコードから不正なバイトコードを生成
- #5: Platypus Finance: 3回の攻撃を幸運で乗り切る
- #6: Hundred Financeインシデント: 脆弱なフォークされたプロトコルにおける精度関連エクスプロイトの波を触媒
- #7: ParaSpaceインシデント: 業界で最も致命的な攻撃を阻止するための時間との戦い
- #8: SushiSwapインシデント: 不器用な救助の試みが一連のコピーキャット攻撃につながる
- #9: MEV Bot 0xd61492: 捕食者から犠牲者へ、巧妙なエクスプロイトで



