GeminiのPythonサンドボックスをハックしてソースコードの一部を流出させた
(landh.tech)- LupinとJustinは、Googleの2024年Las Vegas LLM bugSWATでGeminiプレビューのPythonサンドボックスを調査し、
/usr/bin/entry/entry_pointと内部ファイル構造を抽出し、この脆弱性によってMost Valuable Hackerを受賞した - サンドボックスはgVisorとGRTEベースで外部ネットワークが遮断されていたが、ユーザーコードが
osモジュールでファイルシステムを走査できたため、内部バイナリをコンソール出力チャンクとして持ち出せた - 579MBの
entry_pointは直接出力するとタイムアウトが発生するため、seek()とbase64エンコードで10MB単位チャンクを作り、Caido Automateでリクエストを繰り返してローカルで再構成した - Binwalkの分析で
google3ディレクトリとGeminiサンドボックス関連のPythonコードが明らかになり、公開承認済みのコードとは別に、classification.protoや複数のセキュリティproto定義が意図せず含まれた機密内部情報だった - サンドボックスがGoogle FlightsのようなツールとRPCで接続される構造や、より権限の高いエージェント用サンドボックスにアクセスできる可能性も確認されたが、疑われた内部ファイル読み取りハンドラはRPCでは利用できず、外部からのみ呼び出し可能だった
bugSWAT 2024とGeminiプレビューへのアクセス
- LupinとJustinは、2024年のLas Vegasで開催されたGoogle LLM bugSWATイベントで、Geminiの次回アップデートのプレビューに早期アクセスした
- Googleチームは新機能と意図された動作をまとめた文書を提供し、研究者たちの目標は攻撃者の視点で機能を探索しテストすることだった
- 簡単なプロンプト
run hello world in python3で始めると、Geminiはコードを生成し、インターフェースにRun in Sandboxボタンを表示した - この脆弱性研究の結果として、2人はそのLas Vegas bugSWATでMost Valuable Hackerの称号を得た
Gemini Pythonサンドボックスの基本構造
- 当時のGeminiは、AIが生成したPythonコードやユーザーが直接書いたスクリプトをGemini環境内で実行するPython Sandbox Interpreterを提供していた
- サンドボックスはGoogleのgVisorとGRTE(Google Runtime Environment)を基盤に構成されていた
- gVisorは、コンテナ化されたアプリケーションとホストOSの間でシステムコールを横取りするユーザー空間カーネルである
- 従来のOSレベル隔離だけに依存せず、最小限のカーネル機能サブセットを実装することで攻撃面を減らす
- 研究者たちはgVisorサンドボックス脱出を別の高難度問題と見なし、サンドボックス脱出は最大**$100kバウンティ**の対象になり得た
- 今回のアプローチはサンドボックスを脱出する代わりに、サンドボックス内部に外部へ露出してはいけないデータがないかを探すものだった
- 中核となる制約は、サンドボックスがカスタムコンパイルされたPythonバイナリしか実行できない点だった
ファイルシステムのマッピングとentry_pointの発見
- フロントエンドでPythonコードを完全に書き換えることで、サンドボックス内で任意バージョンを実行できた
- シェルは起動できなかったが、カスタムPythonバイナリに
osモジュールが含まれていたため、ファイルシステムのマッピングが可能だった - 研究者たちは、再帰的にファイルとディレクトリを列挙し、サイズと権限を出力するPython関数を書いた
lslR("/usr")の呼び出し結果から、/usr/bin/entry/entry_pointにあるバイナリファイルを発見した- このファイルは579MBあり、その後の分析の中心対象となった
ネットワークなしでバイナリを流出させた方法
entry_pointをそのままbase64エンコードしてフロントエンドへ出力しようとすると、サンドボックスが停止し、最終的にタイムアウトした- TCP、HTTP、DNSを使った外部流出の試みはすべて失敗し、サンドボックスは外部ネットワークから完全に隔離されているように見えた
- 外部呼び出しが塞がれた状況で、研究者たちはコンソール出力でバイナリを分割して流出させる方法を選んだ
seek()でバイナリ位置を移動しながら読み込み、base64でエンコードして10MB単位チャンクとして出力した- Caidoをプロキシとして使い、サンドボックス呼び出しリクエストと結果を捕捉し、Automate機能でリクエストを繰り返し送信した
- Automateは、リクエストを大量送信し、特定パラメータを高速に変更できる機能である
- すべてのbase64チャンクを集めた後、ローカルで全ファイルを再構成した
entry_pointの分析結果
fileコマンドは、このファイルをELF 64-bit LSB shared object, x86-64, version 1 (SYSV)形式の動的リンクバイナリと識別したstringsコマンドの出力には、Google内部リポジトリを指すgoogle3への参照が何度も現れた- これらの参照は、内部データパスとコード断片の存在を示唆し、バイナリにGoogle独自ソフトウェアの痕跡が含まれていることを示していた
- Binwalkが決定的な手がかりを与えた
- バイナリ内部から完全なファイル構造を抽出した
- 抽出結果からサンドボックスのレイアウトと内部コンポーネントが明らかになった
google3ディレクトリとGemini関連Pythonコード
- Binwalkで抽出したディレクトリ内には
google3ディレクトリがあり、assistant、base、devtools、file、google、net、pyglib、testing、third_party、utilなどのサブディレクトリが含まれていた assistantディレクトリでは、YouTube、Google Flights、Google Mapsのようなツール要求処理に使われるRPC関連Geminiコードが見つかった- 特に
google3/assistant/boq/lamda/execution_box/配下には、サンドボックス実行、画像処理、ツール利用、RPCインターフェースに関するPythonファイルが存在した google3/assistant/boq/lamda/execution_box/images/py_interpreter.pyには、無断スクリプトダンプ検知用と見られる文字列を含むコードがあった- その文字列は
"3AVp#dzcQj$U?uLOj+Gl]GlY<+Z8DnKh"だった
- その文字列は
- 後のレビューでは、このPythonコードの内部Google3同梱は、リリース前の公開露出としてGoogle Security Teamが承認した選択だったと整理された
- このコードにはダンプ防止メカニズムのように見える要素があったが、公開露出自体は承認済みだった
サンドボックスとGoogleツールRPC構造
- さらに深い分析により、サンドボックスがGoogle FlightsのようなGoogleサービスのデータを取得するため、外部のGoogleサーバーと通信する構造が確認された
- この通信は
google3.assistant.boq.lamda.execution_box.sandbox_interfaceのPythonクラスを通じて実装されていた _set_reader_and_writerのような関数は、RPC用のreaderとwriterハンドルを設定する- 既定動作は
/dev/fd/3と/dev/fd/4を使う方式として現れていた
- 既定動作は
run_tool(name, operation_id, parameters)は、ツール名、操作ID、パラメータを受け取り、RunToolRequestを作成してRPCリクエストとして送る- これらの関数は、データをprotobuf互換形式にシリアライズしてローカルファイルディスクリプタ
5へ書き込み、応答をファイルディスクリプタ7から読む方式で動作していた - 大きなバイナリ内で見つかったprotoを使って、研究者たちはRPCサーバーとやり取りするメッセージを作成し、Googleツールを直接呼び出せた
エージェント用サンドボックスと権限差
- すべてのサンドボックスが同じGoogleサービス群へアクセスできたわけではなかった
- その違いは、サンドボックスがフロントエンドでPythonソースコードを実行するために作成されたのか、Google Agentによって生成されたのかで変わった
- Googleチームは、Geminiの基盤研究としてREACT: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELSを示した
- ReActアプローチは、言語モデルが推論の痕跡を生成し、特定の行動を実行する過程を交互に繰り返す構造である
- モデルは問題を解きながら計画を立て、外部ソースと相互作用して必要なデータを取得する
- 質疑応答、事実検証、テキストベースゲーム、Web探索などに適用されるフレームワークとして紹介されている
- ユーザーがTorontoとNew Yorkの間で最も早い便を尋ねた場合、Geminiはおおむね次の流れを取る可能性がある
- ユーザーの意図をフライト検索だと解釈する
- Google Flightsツールへ接続するPythonコードを計画する
- YYZからJFKまで、今日から来週までの便を探し、日付順に並べるコードを生成する
- 必要な権限を持つサンドボックスを作成してコードを実行する
- 出力結果を処理してユーザーに応答する
二次プロンプトインジェクション実験と限界
- 研究者たちは、Geminiの計画段階に二次プロンプトインジェクションを仕掛け、より高権限のサンドボックスへアクセスできるかを実験した
- Google Security Teamの支援のもとでテストした結果、生成シードやtemperatureなどの確率的要素により、より高権限のサンドボックスに見える環境へ時折アクセスできた
- ここでいう高権限サンドボックスとは、拡張機能へアクセスするための2つの新しいファイルディスクリプタを使える環境を指す
- ファイルディスクリプタ自体は常に存在していたが、常に実際にlistenしているわけではなかった
- エージェントがサンドボックスを呼び出すときは、Googleサービス拡張呼び出しを監視してAPIとやり取りできる
- Pythonインタープリタからアクセスした場合、その拡張機能は利用できなかった
- 研究者たちは、特定のメッセージハンドラがGoogle内部インフラ上でファイル読み取りを許可し得ると見て、P0の可能性を期待した
- Google Security Teamのレビューの結果、その疑わしいハンドラはRPCでは利用できず、外部からのみ呼び出せることが確認された
- 実験は限定的だったが、コード実行は次の可能性を開き得た
- Reliability: コードを実行すると挙動をより一貫してトリガーできる
- Chaining/Complexity: 複数ツールの制御やパラメータ調整を、テキストより複雑に構成できる
- Tool Output Poisoning: ツール出力の改ざんをより効果的に試みられる
- Leaks: 環境の隠れた部分が露出すると追加の利点を与え得る
実際に露出したprotoファイル
- 研究者たちは、複数の方法でprotoファイルを流出させられることを確認した
- protoファイルはProtocol Bufferファイルであり、システムのメッセージ構造と情報交換方式を定義する設計図の役割を果たす
strings entry_point > stringsoutput.txtを実行した後、Dogfoodを検索して内部protoの一部を見つけた- 抽出された内容の一部には、非常に機密性の高いprotoのメタデータ説明が含まれていた
- ユーザーデータそのものは含まれていなかった
- Googleがユーザーデータを分類するために使う内部カテゴリだった
Dogfoodは、Googleが一般公開前に自社製品やプロトタイプを社内利用してテスト・改善する慣行を指す- 露出したファイルの1つは
privacy/data_governance/attributes/proto/classification.protoだった- このファイルは、Google内部でデータがどのように分類されるかを扱っていた
- 関連文書への参照も含まれていたが、それらの文書は機密であり公開アクセス対象ではなかった
内部セキュリティproto定義の露出
- 同じ
strings出力から、公開されるべきでない複数の内部protoファイルも明らかになった cat stringsoutput.txt| grep '\.proto' | grep 'security'コマンドにより、次のような機密ファイルパスが現れたsecurity/thinmint/proto/core/thinmint_core.protosecurity/thinmint/proto/thinmint.protosecurity/credentials/proto/authenticator.protosecurity/data_access/proto/standard_dat_scope.protosecurity/loas/l2/proto/credstype.protosecurity/credentials/proto/end_user_credentials.protosecurity/loas/l2/proto/usertype.protosecurity/credentials/proto/iam_request_attributes.protosecurity/util/proto/permission.protosecurity/loas/l2/proto/common.protoops/security/sst/signalserver/proto/ss_data.protosecurity/credentials/proto/data_access_token_scope.protosecurity/loas/l2/proto/identity_types.protosecurity/credentials/proto/principal.protosecurity/loas/l2/proto/instance.protosecurity/credentials/proto/justification.proto
- バイナリ文字列中で
security/credentials/proto/authenticator.protoを確認すると、そのデータが実際に露出していたことが分かった
なぜprotoがバイナリに入っていたのか
- Google Security Teamはサンドボックス内の内容をレビューし、公開disclosureへの承認を与えていた
- しかし、サンドボックス用バイナリのコンパイルビルドパイプラインには、内部ルール執行に必要と判断された場合にsecurity protoファイルをバイナリへ追加する自動ステップがあった
- 今回はそのステップが必要なかったにもかかわらず、結果として非常に機密性の高い内部protoが意図せず含まれてしまった
- 研究者たちは、Googleがこの種のprotoを公開されてはならない高機密情報として扱っていることを知っていたため、これをバグとして報告した
- 対象組織のビジネスルールとセキュリティ優先順位を深く理解していなければ、このような微妙な露出を識別して報告することは難しい
結論と実務的示唆
- リリース前の先端AIシステムは、機能動作だけでなく内部成果物まで徹底的にテストする必要がある
- 一見単純なサンドボックスでも、複数の拡張機能と接続されると予期しない露出経路が生まれ得る
- 複数コンポーネントが連携して動作するとき、小さな見落としが新たな問題経路を生むことがある
- 今回の事例では、公開承認済みの内部コードと、意図せず含まれた機密protoが区別され、後者が実際のセキュリティ報告の核心となった
- AIエージェント、サンドボックス実行、ツール呼び出し、内部RPCが組み合わさる環境では、実行隔離だけでなくサンドボックス内部資産とビルド成果物まで見直す必要がある
まだコメントはありません。