セキュリティとプライバシー

Google DevSite の RCE: 漏洩したシークレットがリモートコード実行を可能にした経緯

研究者が Google の DevSite プラットフォームに重大な脆弱性を発見しました。OAuth クライアントシークレットがセッション Cookie の署名に使用されており、複数のドメインでリモートコード実行が可能になっていました。

サーバー上でコードを漏洩させている破損したセッション Cookie の概念図
この記事用に生成されたイラスト

英語の原文から自動翻訳されました。

セキュリティ研究者の Simon Koeck は、2026 年 8 月に Google の共有 DevSite プラットフォームにおいて、重大なリモートコード実行 (RCE) 脆弱性を発見しました。この欠陥により、攻撃者は Firebase や Android などのサービス向け開発者ドキュメントをホストするサーバー上で、Flask セッション Cookie の設定ミスを利用し、任意のコードを実行することができました。Google は、この問題が高-profile なサブドメイン複数に影響することを確認した後、Koeck に報告に対して 90,000 ドルを支払いました。

何が起きたか

Koeck は、developers.google.com を含む Google の開発者ドキュメントサイト全体で使用されている OAuth 認証フローのマッピングを行っていました。彼は、OAuth ハンドシェイク中に発行される Flask セッション Cookie が約 1,200 バイトと異常に大きいことに気づきました。Flask Cookie は署名されますが暗号化されないため、ペイロードをデコードして内容を確認しました。その内部には、oauth2client.client.OAuth2WebServerFlow インスタンスを含む pickle シリアライズされたオブジェクトが見つかりました。重要なのは、このオブジェクトが Google OAuth の client_id と client_secret を平文で保持していたことです。

クライアントサイドの Cookie にクライアントシークレットが存在すること自体、すでに重大なセキュリティ上の発見でした。しかし、Koeck はこのシークレットが Cookie 自体の署名用 Flask SECRET_KEY としても使用されているかどうかをテストした際、影響がさらに深刻であることを認識しました。Flask の標準的な itsdangerous ライブラリのロジックを使用して、露出したクライアントシークレットから署名キーを導出し、Cookie の署名をオフラインで再現することに成功しました。これは、サーバーが保護しようとしているデータ自体の中に格納されているシークレットを用いて、そのデータの整合性を検証していたことを意味します。

有効なセッション署名を偽造できる能力を得た Koeck は、意図されたセキュリティ制御を回避することができました。アプリケーションロジックはセッションから OAuth フローオブジェクトを取得し、pickle.loads() を使用してそれをデシリアライズしていました。Python の pickle モジュールは、特定のオペコードに遭遇するとデシリアライズ中に任意のコードを実行できる可能性があり、かつ Koeck は現在有効に署名された Cookie を作成できたため、認証なしのリモートコード実行を達成しました。彼は、サーバーが特定の時間スリープするようにさせるペイロードを注入することでこれを証明し、本番環境の機密データにアクセスせずにバックエンドでコードが実行されていることを示しました。

仕組み

この脆弱性は、3 つの具体的な設定ミスの連鎖に依存していました。第一に、アプリケーションは機微な資格情報(OAuth クライアントシークレット)をユーザーのセッション Cookie に直接保存していました。第二に、同じクライアントシークレットをセッション Cookie の署名用の暗号鍵として使用しており、Cookie を検査すれば誰でも鍵を知ることができるという循環依存を生み出していました。第三に、アプリケーションは Python の pickle モジュールを使用して Cookie からユーザー制御のデータをデシリアライズしており、これは読み込みプロセス中のオブジェクトインスタンス化やメソッド呼び出しを許可するため、信頼できない入力に対して本質的に安全ではありません。

Flask は Cookie の署名に itsdangerous ライブラリを使用し、通常は HMAC-SHA1 を使って主要な SECRET_KEY から特定の署名キーを導出します。Koeck は漏洩したクライアントシークレットを使用してこの導出をローカルで再現しました。署名が一致することを確認した後、彼は新しいセッション Cookie を作成しました。期待されるセッションキーの下に悪意のある pickle ペイロードを挿入し、導出されたキーで署名してサーバーに送信しました。サーバーは署名を正常に検証し、pickle を抽出して埋め込まれた指示(例えば time.sleep() の呼び出しなど)を実行しました。

主要な詳細

  • この脆弱性は共有 DevSite プラットフォームに存在し、developers.google.com、firebase.google.com、developer.android.com、source.android.com、および docs.partner.android.com に影響を与えました。
  • Flask セッション Cookie には、ライブの OAuth client_secret を平文で含む pickle シリアライズされた OAuth2WebServerFlow オブジェクトが含まれていました。
  • OAuth client_secret はセッション Cookie の署名用に Flask SECRET_KEY として使用されており、攻撃者が有効なセッションを偽造することを可能にしていました。
  • リモートコード実行は time.sleep(N) ペイロードを使用して証明され、サーバーの応答時間が注入されたスリープ時間と完全に一致しました。
  • Google はこの問題を S0(クリティカル)RCE と分類し、75,000 ドルの基本額に報告品質に対する 1.2 倍の乗数を加算して計算された 90,000 ドルのバウンティを支払いました。
  • 修正には、シークレットのローテーション、署名キーと OAuth 資格情報の分離、フローオブジェクトのサーバー側ストレージ、および pickle の安全なデータ形式への置き換えが含まれていました。

なぜ重要なのか

この事案は、信頼境界を越えるデータに対して pickle のような複雑なシリアライズ形式を使用することの危険性を浮き彫りにしています。Pickle は Python オブジェクトの状態を保存するのに便利ですが、デシリアライズ中にどのクラスや関数を呼び出せるかを制限するメカニズムを提供しません。侵害された署名キーと組み合わせると、それはリモートコード実行への直接的な道となります。開発者はしばしば署名付き Cookie が改ざん防止であると仮定しますが、署名キーが漏洩したり不適切に管理されたりした場合、その保証は完全に失われます。

エンジニアリングチームにとって、これはシークレットの管理とローテーションの方法を監査するための警告です。API 認証とセッション署名など、単一の資格情報を複数の目的で使用することは、単一の漏洩時の影響範囲(blast radius)を広げます。また、機微な状態をサーバー側に保持することの重要性も強調しています。特に Google OAuth のようなサードパーティプロバイダーを含む認証フローを扱う場合、Cookie には不透明な参照のみ、または最小限の非機密データを含めるべきです。

あなたができること

  • API シークレットや OAuth トークンなど他の資格情報とは異なる署名キーを使用していることを確認するために、アプリケーションのセッション管理を監査してください。
  • クライアントへ移動したり信頼境界を越えたりするすべてのデータについて、pickle を JSON や Protocol Buffers などの安全なシリアライズ形式に置き換えてください。
  • OAuth フローオブジェクトなどの機微な状態は、クライアントサイドの Cookie ではなく、サーバー側のセッションやキャッシュに保存してください。
  • 厳格なコンテンツセキュリティポリシーを実装し、時間ベースのブラインド RCE 試行を示唆する可能性のある異常なレイテンシパターンを監視してください。
  • 漏洩が疑われる場合は、露出したすべてのシークレットを直ちにローテーションし、それらのキーで署名された既存のセッションを無効化してください。
  • 信頼できない入力に対する pickle.loads() のような安全でないデシリアライズメソッドの使用を検出するために、静的解析ツールを使用してください。

Bytechapストアのツール

続きを読む

すべての記事