Wormholeブリッジハック:3億2600万ドルのエクスプロイト技術分析
2022年2月2日、Wormholeのトークンブリッジは12万wETH(当時約3億2600万ドル)を失い、DeFi史上最大級のスマートコントラクトエクスプロイトの一つとなりました。この攻撃に盗まれたキー、ソーシャルエンジニアリング、Guardianバリデータネットワークの過半数支配は不要でした。必要だったのは1つ、廃止されたSolanaプログラムAPIで、どのアカウントから読み取っているかの検証に失敗していたことです。
このエクスプロイトを理解することは、Solana上で構築するすべてのチーム、クロスチェーンメッセージングに依存するすべてのプロトコル、Solanaプログラムを監査するすべての監査人にとって必須です。根本原因はWormholeのSolanaブリッジプログラムにおけるスマートコントラクトの検証欠陥であり、キーの漏洩やGuardianネットワークの障害ではありません。Guardianのキーは一切触れられておらず、ブリッジの自身のコードが攻撃者に決して与えてはいけない認可を渡してしまいました。
Wormholeハックにおける主な技術的脆弱性は何だったのか?
脆弱性はWormholeのSolanaブリッジプログラム(bridge.so)のverify_signatures命令に存在しました。この関数は、GuardianノードからのEd25519またはSecp256k1署名を含むSignatureSetアカウントが真正なコンセンサスを表すことを検証し、Verifiable Action Approval(VAA)を認可する役割を担っていました。
欠陥は、verify_signaturesが非推奨のsolana_program::sysvar::instructions::load_instruction_at関数を使って、同一トランザクション内でSecp256k1の事前検証命令が呼ばれていることをチェックしていた点です。この非推奨関数は渡されたアカウントが実際にSolanaのinstructions sysvar(Sysvar1nstructions1111111111111111111111111)であるかを検証せず、指定されたインデックスにあるアカウントからデータを読み取るため、呼び出し元が完全にコントロールするアカウントも読み込めてしまいます。
攻撃者は、指示された位置に自作のアカウントを置き、攻撃者が制御する署名データを攻撃者選択のペイロード上に予め格納したアカウントを渡すことが可能です。関数は偽のデータを読み取り、Secp256k1呼び出しが「存在する」と判断して(まったく別の文脈で)、VAAをGuardian承認済みとマークし、成功を返します。
この不正に承認されたVAAを手にした攻撃者はcomplete_wrappedを呼び出し、ブリッジプログラムのVAA承認を信頼してSolana上でラップトークンのミントを認可しました。その結果、Ethereum上にロックされたETHがないまま12万wETHがミントされてしまったのです。
修正は、load_instruction_atをload_instruction_at_checkedに置き換えるもので、後者はアカウントが正真正銘のinstructions sysvarであることを強制的に検証します。修正コードはエクスプロイト発生前にWormholeのGitHubリポジトリにコミット済みでしたが、メインネットにはまだデプロイされていませんでした。
| 要因 | 説明 | 影響 |
|---|---|---|
非推奨のsysvar API |
_checked無しのload_instruction_at - 指定インデックスに渡されたアカウントの所有者検証なし |
攻撃者が本物のinstructions sysvarの代わりに偽造アカウントを供給可能 |
verify_signaturesのバイパス |
行き先不明のアカウントから攻撃者製のSignatureSetをGuardianコンセンサス証明として検証なしで受理 |
真のGuardian署名なしにミント承認が付与された |
アカウント所有者検証欠如 |
SignatureSetアカウントがinstructions sysvarプログラムに所有されているか検証されていなかった |
この検証欠如がエクスプロイトの根幹を成す |
Wrappedトークンミント権限 |
Solanaブリッジプログラムがラップトークンの無制限ミント権限を持ち、承認にはVAAが承認済みとしてマークされていれば十分だった | EthereumにETHロックなしで12万wETHをSolana上でミント、約3億2600万ドル相当 |
WormholeハックとRoninのような他のブリッジ攻撃との違いは?
Roninブリッジハック(2022年3月、約6億2500万ドル)は、ブリッジセキュリティ失敗の議論でWormholeとよくセットで語られますが、根本的に異なる失敗形態です。
WormholeはSolanaブリッジプログラムのスマートコントラクト検証バグでした。Guardianネットワーク(19ノードの閾値署名スキーム)は一切侵害されていません。攻撃者はverify_signaturesがどのアカウントから読んでいるかをチェックしなかったことを突いて、Guardianを完全にバイパスしました。Guardianキーは無傷でネットワークも稼働しており、実際のGuardianコンセンサスは一切参照されませんでした。
Roninは運用キー窃盗でした。Sky MavisはRoninの9ノード中5ノードを運営。2021年11月にAxie DAOは一時的にトランザクション負荷対応のためSky Mavisに署名権限を委譲。期間満了後も解除されていませんでした。攻撃者(後にLazarus Groupと特定)がSky Mavisの内部システムを侵害し4つのバリデータキーを入手。Axie DAOの権限委譲経由で5つ目の署名をSky Mavisのガス不要RPCノードで取得。合計5/9署名を揃えた有効な署名でRoninブリッジコントラクトに正当な出金メッセージを提出しました。スマートコントラクトバグの悪用はなく、ブリッジは本来通り正当署名での出金を承認しただけです。
| Wormhole(2022年2月) | Ronin(2022年3月) | |
|---|---|---|
| 攻撃ベクター | Solanaプログラムアカウント検証バイパス | Sky Mavisノードのソーシャルエンジニアリングと資格情報漏洩 |
| エクスプロイト手法 | 非推奨sysvar APIを利用した偽造SignatureSetアカウント |
盗難されたバリデータキーによる正当な署名済み出金 |
| Guardian/バリデータネットワーク | 完全無傷(攻撃コードによりバイパス) | 侵害済み(攻撃者が9ノード中5ノードのキーを保持) |
| 影響の出し方 | EthereumにETHロックなしでSolana上で無許可ミント | 正当署名によるRoninブリッジコントラクトからの直接引き出し |
| 窃取額 | 約3億2600万ドル(12万wETH) | 約6億2500万ドル(173,600 ETH + 2550万USDC) |
| セキュリティ教訓 | Solanaプログラムではアカウント所有権検証は必須。閾値署名はブリッジが実際に読み取る場合のみ効果あり | 閾値署名スキームは過半数キー漏洩に無力。権限委譲撤回も確実に管理すべき |
Wormholeエクスプロイトの実行手順
-
アカウント偽装。 攻撃者はWormholeブリッジプログラムの命令データ内
SignatureSetの位置に期待されるレイアウトを模したSolanaアカウントを作成。ここに有効なEd25519/Secp256k1署名(攻撃者自身が署名し、攻撃者選択のVAAペイロード上)を格納。VAAは攻撃者のSolanaアドレスへの12万wETHミントを承認。 -
非推奨sysvar APIのバイパス。 攻撃者は
verify_signatures呼び出し付きのトランザクションを送信。プログラムは事前検証に非推奨かつ検証なしのload_instruction_atを呼び、同一トランザクション内のSecp256k1命令の呼び出し有無をチェック。load_instruction_atは指定インデックスに置かれたアカウントの正体を検証せずデータを読み取る。 -
偽造証明が受理。
verify_signaturesは攻撃者管理アカウント内の署名を順に検証し、すべて暗号的に正当(攻撃者自身が自作データに署名)と判断し、VAAをGuardian承認済みにマーク。Guardianネットワークは一切参照されず。 -
ミントを承認。 攻撃者は承認済みVAAで
complete_wrappedを呼び出し。ブリッジプログラムはVAA承認状態を信頼し、攻撃者のSolanaアドレスに12万wETHをミント。 -
クロスチェーン出金。 攻撃者はミントされたwETHをWormholeの正規のクロスチェーンフローを通じてEthereumへブリッジ。Solanaウォレット内にwETHが存在するため、ブリッジは通常通りの出金処理を実施。3億2600万ドル相当の裏付けなきwETHはEthereumに着地後、ETHやステーブルコインに交換されて換金された。Wormhole親会社Jump Cryptoは自己準備金から12万ETHを補填しブリッジ利用者を救済。
Solanaプログラムおよびクロスチェーンブリッジに対する最も重要な技術的教訓
1. Solanaプログラムに渡されるすべてのAccountInfoは、検証されるまで攻撃者に制御されているとみなす。
これがSolanaプログラムセキュリティの基本ルールです。所有者(owner)、キー(key)、場合によってはexecutableやis_signerフィールドを必ず検証しなければなりません。非推奨のload_instruction_atは指定インデックスの任意のアカウントを受け入れていましたが、最新版のload_instruction_at_checkedはアカウントが本物のinstructions sysvarであることを強制的に検証します。SokenのSolana監査では非_checked系sysvar API使用は文脈を問わず重大な所見に指定します。
2. 署名検証と資産ミントの権限は分離すべき。
ブリッジのミント権限は、プログラム自身が管理する正式な状態から証明を再導出する検証モジュールの背後に置くべきです。verify_signaturesが攻撃者管理アカウントを真実の根拠として受け入れたことで「ネットワークが承認したか」と「ミントできるか」の分離が崩壊しました。ミント命令は本物のGuardian入力を検証した結果から作成された状態に基づくべきです。
3. VAAのリプレイ防止はオンチェーンで強制されるべき。
仮にSignatureSetが本物でも、complete_wrappedは既に消費されたVAAハッシュを拒否すべきでした。Wormholeは後続バージョンでリプレイ防止を追加しましたが、エクスプロイト時点では不在であり、不正承認VAAが何度も使い回せてしまいました。すべてのブリッジアクションは、実行開始時に原子的に更新されるprocessed_vaas: mapping[bytes32, bool]等の消費済みVAA管理を通じて制御されるべきです。
4. 非推奨APIの使用は重大な監査指摘。
Wormholeの脆弱性は既知の非推奨機能でした。Solana SDKはload_instruction_atの非推奨を警告し、_checked版を用意していました。古いAPIを放置するのはコード品質の問題ではなく、攻撃者がログや未デプロイコミットの差分から積極的に探すセキュリティ上の重大欠陥です。Solana監査では必ずsolana_program::sysvar::instructions::*の非_checked版を検出し、発見時は重大指摘として対応します。これは2022年以降のOttersec、Halborn、SokenのあらゆるSolana監査で標準です。
5. 未デプロイのセキュリティ修正は公然の攻撃マップ。
load_instruction_at_checkedによる修正はエクスプロイト発生前にWormholeのパブリックリポジトリにコミットされていました。高度な攻撃者は対象プロトコルのセキュリティ関連コミットを監視し、非推奨APIから検証版への代替差分を追跡して脆弱性を特定できます。セキュリティクリティカルなプログラムのデプロイパイプラインは「mainにマージ済み」から「メインネットに展開済み」までを露出ウィンドウとみなし、緊急展開手順により数時間で閉じるべきです。
6. 閾値マルチシグはアカウント検証の欠陥を補えない。
WormholeのGuardianネットワークは19ノードの閾値署名スキームで堅牢でしたが、この攻撃には全く無意味でした。攻撃はverify_signaturesが読んでいるアカウントを操作してコンセンサス層全体を迂回したためです。閾値署名はGuardianキー侵害に対して防御を提供しますが、Guardianに一切問い合わせないバグには無力です。防御層の一つ一つを確実に起動させることが防御の本質であり、回避された制御は制御ではありません。
ブリッジ監査とSolanaプログラムセキュリティにおける意味
Wormholeのエクスプロイトはクロスチェーンブリッジセキュリティが多層的な問題であることを示しました。Guardianネットワークが暗号的に健全で、経済的インセンティブが適切に調整され、プロトコル設計が優れていても、オンチェーンプログラムのわずかな非推奨関数呼び出しで全てが無効化されます。
Solana上で構築するチームは、アカウント検証の教訓を一般化させるべきです。プログラムに渡される全パラメータを敵対的入力と見なし、操作前に所有者、キー、ディスクリミネータ、データ長を検証してください。AnchorフレームワークのAccount<T>ラッパーや同等の仕組みを使い、手動アサーションではなく型レベルでの検証を強制しましょう。
ブリッジ設計者にとっては権限分離と正式状態への固定が鍵です。ミント権限はプログラム自身が検証したプログラム所有状態に由来すべきであり、検証なしに受け入れた呼び出し元提供の証明であってはなりません。
SokenはすべてのSolanaプログラムを対象に、非推奨sysvar API使用、アカウント所有者検証欠落、VAAリプレイ防止の欠如を重大指摘項目として監査しています。verify_signaturesが読むアカウントを操作して閾値マルチシグをバイパスするパターンは、SokenのSolana監査手法で新たな攻撃クラス名付きで認定済みです。クロスチェーンメッセージングやラップトークンミントを利用するプロトコルは、soken.dev/services-it.htmlより展開前のセキュリティレビューをぜひご相談ください。