autorenew
Solana PDA なりすまし:チェック漏れがローンチパッドでトークン窃盗を招いた仕組み

Solana PDA なりすまし:チェック漏れがローンチパッドでトークン窃盗を招いた仕組み

高速なトランザクションと革新的なDeFiツールが交差するSolana開発の世界では、コードの小さな見落としが大きな悪用につながることがあります。まさにそれが、3月に行われたMetaDAOのローンチパッド監査で起きたことです—Program Derived Addresses(PDA)に関する微妙なバグにより、攻撃者が新規鋳造されたトークンを吸い上げることができてしまいました。Solanaのセキュリティ企業Accretionによる「Advent of Bugs」シリーズのDay 1で明かされたこの話は、署名者の検証を二重に確認する重要性を再認識させるものです。

Solanaのスマートコントラクトに深く関わっている方も、単にこのようなプラットフォームでミームトークンのローンチに興味を持ち始めた方も、ここで読み進めてください。何がまずかったのかを分解し、攻撃のステップを順を追って説明し、プロジェクトを守るための重要な教訓を共有します。博士号は不要—必要なのは明快で実践的なインサイトです。

セットアップ:ローンチパッドのPDAへの信頼

MetaDAOのローンチパッドは、トークンローンチをスムーズで分散化されたものにするために設計されています。これは、Solana上で急速に広まっているミームコインのドロップに似た構造です。新しいローンチを初期化するとき、プログラムは launch_signer と呼ばれる特別なアカウントを作成します。これは単なるアカウントではなく、ローンチのキーと固定のシード文字列("launch_signer")から導出されるPDAです。PDAはプライベートキーを持たない「署名者」を作るSolanaの方法であり、決定論的なシードによりプログラムロジックだけがそれを制御できるようにします。

アイデアはシンプルです:launch_signer PDA が新しいトークンの mint authority として機能します。初回トークンを所定のアカウントに鋳造してローンチを開始する際、プログラムは Solana の invoke_signed 関数を使い、提供したシードを用いて PDA を「署名」させます。

しかし、ここで問題が起きました。指示(instruction)は、提供された launch_signer アカウントが実際に期待される PDA アドレスと一致しているかを明示的に検証していなかったのです。代わりに、シードを invoke_signed に渡せばそれで全て処理されると信頼していました。結論:そうではありませんでした。

暴かれたバグ:署名者のなりすまし

Accretion の監査チームは隙間を見つけました:プログラムは launch_signer を unchecked account(UncheckedAccount)として扱っており、そのアドレスに対する組み込みの検証がなかったという点です。これにより、トランザクション内でトップレベルの署名者であり、かつ mint の権限と一致する限り、任意の Solana アカウントを渡せてしまいます。

なぜこれが問題なのか?Solana では、シードが一致しない状態で invoke_signed を使っても、もしそのアカウントが既に外側のトランザクションに署名していれば関数は失敗しません。シードは無視され、攻撃者のキーペアによる実際の署名が効力を持ちます。これで—なりすましが成立します。

これは理論上の稀なケースではありません。トークン mint への裏口がそのまま開いてしまうのです。

実際の攻撃:ローンチ前にトークンを盗む手口

熱い新しいミームトークンのローンチを狙う攻撃者を想像してみてください。攻撃手順は以下の通りです:

  1. Prep Your Trap:新しい mint アカウントを作り、あなた自身のキーペア(以下 K と呼ぶ)を mint authority に設定します。そして K が所有するトークンアカウントを用意して略奪物を受け取る準備をします。

  2. Trigger the Init:InitializeLaunch 指示を呼び出し、launch_signer に K を渡します。K がトップレベルのトランザクションに署名するのはあなたが制御しているので簡単です。

  3. Mint the Backdoor Supply:プログラムは喜んでトークンをあなたの K 所有アカウントに鋳造します。プログラムは PDA シードで署名していると思い込んでいますが、実際にはあなたのキーペアの署名が効いており、シードは脇に追いやられます。

  4. Cover Your Tracks:目立たないようにするために、盗んだトークンの大部分を戻し、mint authority を本来の PDA に渡してローンチを通常通り進めさせます。あなたは不正な割当を確保し、プロジェクト側は全てが正常だと思い込みます。

ミームトークンの世界では、ローンチが数時間で数百万ドルを動かすこともあります。コミュニティが気づく前にクジラ級のシェアをかすめ取ることが可能になるのです。これぞ「月へ行く」ではなく「攻撃者のウォレットへ行く」ような巧妙な悪用です。

(コードスニペットのうち、欠落していたチェック部分を強調した注釈つきの Rust コードを視覚的に確認したい場合は、以下のスレッドの注釈付きコードを参照してください。)

launch_signer における PDA 導出と検証欠如を示す注釈付き Solana Rust コード

これが起きる理由:Solana の署名の挙動の簡単な解説

PDA に馴染みがない場合、それらをプログラムが制御する「幽霊署名者」と考えてください。PDA は find_program_address を使ってシード(例えば ["launch_signer", launch.key()])から導出され、CPI(Cross-Program Invocation)の際にのみプログラムがシードを使って「署名」できるようにします。

しかし、Solana の柔軟性は両刃の剣です。invoke_signed は PDA のアドレスを ed25519 曲線から外すためにシードを頼りにしています。明示的なアドレスチェック(例:require_keys_eq!(launch_signer.key(), expected_pda))がなければ、攻撃者は自身の署名者を差し替えられます。スレッドの二枚目の画像は、unchecked な mint を含む命令フロー全体を示しています。

unchecked な launch_signer PDA を使ったトークン鋳造の Solana 命令コード

これはまさに「信頼するなら検証せよ」の古典的なケース—コードの世界では常に検証を行うことです。

Solana 開発者とミームトークン構築者への教訓

Accretion の修正内容は単純です:渡された launch_signer が導出された PDA と一致することを確認するチェックを追加すること。これでなりすましは防げます。

特にミームトークンやローンチパッドのような場面でSolana上に構築する人向けの広い教訓は次のとおりです:

  • Always Validate PDAs:invoke_signed を使う際は、期待される PDA を計算し、提供されたアカウントと等しいことを主張(assert)してください。安価で確実です。

  • Ditch Unchecked Accounts Where Possible:UncheckedAccount は柔軟で便利ですが、署名者を扱うときは明示的なチェックと組み合わせて使いましょう。

  • Audit Early, Audit Often:スレッドが示す通り、このバグは初期レビューをすり抜けました。Accretion のような企業はこうした盲点を見つけ出します—次のローンチ前に監査を検討してください。

  • Test the Edges:solana-program-test のようなツールで攻撃をシミュレートし、署名者の不一致を検出しましょう。

ミームトークンのエコシステムでは、熱狂がコードレビューよりも価値を動かすことがあるため、こうした脆弱性がプロジェクトの成否を分けます。MetaDAO は監査後にこの問題を修正しましたが、こうした事例がコミュニティの警戒心を保つ助けになります。

まとめ:セキュリティは積み重ねるもの、バグはそうである必要はない

「Advent of Bugs」シリーズは好スタートを切りました。Solana の高速性が雑なセキュリティを許す理由にはならないことを再確認させてくれます。@r0bre と Accretion チームに敬意を表します—安全でスケーラブルなローンチを目指す開発者にとって非常に価値のある情報です。

Solana プロジェクトを進めていますか?コメントで意見を聞かせてください:PDA の問題に遭遇したことはありますか?あなたの定番の修正方法は何ですか?そしてもし Meme Insider でミームトークンの監査をしているなら、安全なローンチに関する最新情報をぜひご相談ください。

注意を怠らないでください—ブロックチェーンの世界では、たった一つの未検証署名者が千の悪用を生むことがあります。

おすすめ記事