Skip to main content

Gitpod における WebSocket を介したリモートコード実行のゼロデイ脆弱性

著者:
blog-feature-pypi-spoof

2023年2月27日

0 分で読めます

TLDR

この記事では、クラウドベースの開発環境 (CDE) に焦点を当てた現在の Snyk Security Labs の調査プロジェクトについて説明します。これは、Gitpod プラットフォーム上のワークスペースが完全に乗っ取られ、ユーザーの SCM アカウントに拡張されるという結果になりました。この調査で発見された問題は責任を持って Gitpod に開示され、1 営業日以内に解決されました。

クラウド開発環境と Gitpod

パフォーマンスの向上、開発者エクスペリエンス、一貫した開発環境、セットアップ時間の短縮などの利点を求めて、ますます多くの企業がクラウドベースの開発環境を活用し始めています。私たちは、これらのクラウドベースの IDE を採用することによるセキュリティへの影響について考えずにはいられませんでした。

まず、クラウドベースの開発と従来のローカルワークステーションベースの開発の違いと、CDE が開発者セキュリティ環境をどのように変えるかを理解できるように、CDE の動作について簡単に概要を説明します。

従来の開発とは対照的に、CDE は IDE バックエンドを備えたクラウドでホストされたマシン上で実行されます。これにより、通常、IDE の Web アプリケーションバージョンと、SSH 経由でローカルにインストールされた IDE との統合に対するサポートが提供されるため、ユーザーはシームレスで使い慣れたエクスペリエンスが得られます。CDE を使用する場合、組織のコードと開発データベースなどのサポートサービスはクラウド内でホストされます。CDE の情報フローを視覚的に表現した次の図をご覧ください。

blog-websocket-takeover-cde-diagram

ローカルにインストールされた開発環境のセキュリティリスクは今に始まったことではありません。ただし、これまで開発者はあまり注目してきませんでした。2021 年 5 月、Snyk はワンクリックでのデータ漏洩や任意コード実行を引き起こす脆弱な VS Code 拡張機能を開示しました。VS Code や IntelliJ のローカルインスタンスなど、従来のワークステーションベースの開発環境には、ハードウェア障害、データセキュリティ、マルウェアといったその他の情報セキュリティ上の懸念が伴います。このような懸念には、フルディスク暗号化、バージョン管理、バックアップ、マルウェア対策システムを採用することで対処できますが、クラウドベースの開発環境の導入には未解決の問題が数多く残っています。 

  • クラウド IDE ワークスペースがマルウェアに感染したらどうなるでしょうか?

  • アクセス制御が不十分で、ユーザー間または組織間でのワークスペースへのアクセスが許可されていたらどうなりますか?

  • 悪意のある開発者が、組織のデータ損失防止ソフトウェアやエンドポイントセキュリティソフトウェアの認知外のクラウドでホストされているマシンから企業の知的財産を流出させたらどうなるでしょうか?

Snyk の現在のセキュリティ調査プロジェクトでは、クラウドベースの IDE を採用することによるセキュリティへの影響を調べています。この記事では、Gitpod プラットフォームでの最初の調査中に発見された脆弱性の 1 つに関するケーススタディをご紹介します。 

Gitpod プラットフォームの調査

免責事項: 調査用のクラウド IDE ソリューションを検討する際、セルフホストソリューションかクラウドベースのソリューションのいずれかで、研究者にセーフハーバーを提供する明確に定義されたセキュリティポリシーをベンダーが定めているソリューションにすることに決まりました。 

最も普及している CDE の 1 つは Gitpod です。Gitpod は広く採用されており、自動バックアップ、すぐに使える Git 統合、複数の IDE バックエンドなどの拡張された機能セットを備えていることから、調査対象として検討した最初の製品の 1 つになりました。

調査の最初の段階では、Gitpod の基本的なワークフローを理解し、組織を設定して、Burpsuite を使用してトラフィックをキャプチャしながら製品を実験し、さまざまな API とトランザクションを観察しました。次に、GitHub から Gitpod のソースコードを取得して API の内部動作を調査し、関連するアーキテクチャドキュメントを確認して、各コンポーネントとその機能に関する理解を深めました。ここで非常に役に立ったリソースは、Gitpod のアーキテクチャについて手始めに詳しく説明する動画でした。大まかに言うと、Gitpod は Kubernetes 環境にデプロイされた複数のマイクロサービスを活用します。この環境では、各ユーザーワークスペースは専用の一時的なポッドにデプロイされます。 

Gitpod の外部コンポーネントの主要なセットは、ダッシュボード、認証、およびワークスペース、組織、アカウントの作成と管理に関係します。ここでの主要コンポーネントの中心となるのは、server という適切な名前が付けられた TypeScript アプリケーションです。これは WebSocket 経由で JSONRPC API を公開し、この API は、ダッシュボードと呼ばれる React フロントエンドによって使用されます。 

ダッシュボードから、GitHub や Bitbucket などの SCM プロバイダーと簡単に統合して、リポジトリをインポートし、開発環境を立ち上げることができます。その後、ソースコードが提供され、動作する Git 環境が提供されます。ワークスペースがプロビジョニングされると、ws-proxy と呼ばれる Golang ベースのコンポーネントを介して、gitpod.io のサブドメイン (つまり https://[ワークスペース名].[クラスター名].gitpod.io) 上の SSH および HTTPS 経由でアクセスできるようになります。 

Snyk の調査で発見されたセキュリティ脆弱性は、主に server コンポーネントと WebSocket 接続を介して提供される JSONRPC に関連しており、最終的に Gitpod でのワークスペースの乗っ取りにつながりました。

技術的な詳細

WebSocket と同一オリジンポリシー

WebSocket は、クライアント (通常は Web ブラウザー) とサーバー間のリアルタイムの双方向通信を可能にするテクノロジーです。これにより、クライアントとサーバー間の永続的な接続が可能になり、HTTP リクエストを繰り返す必要なく継続的な「リアルタイム」データ転送を行うことができます。 

セキュリティの観点における WebSocket の興味深い側面は、ブラウザーのセキュリティメカニズムである同一オリジンポリシー (SOP) が適用されないことです。これは、Web サイトが別の Web サイトに AJAX リクエストを発行してその応答を読み取ることを防ぐセキュリティ制御です。これが可能だと、ブラウザーは通常、すべてのリクエスト (CSRF 関連攻撃などのクロスオリジンリクエストも含む) とともに Cookie を送信するため、セキュリティ上の懸念が生じます。SOP がない場合、どの Web サイトも、海外の Web サイトにリクエストを発行して、他のドメインからデータを取得することが可能になります。

これは、クロスサイト WebSocket ハイジャックとして知られる脆弱性クラスにつながります。この攻撃は、クロスサイトリクエストフォージェリと CORS の構成ミスを組み合わせたものに似ています。WebSocket ハンドシェイクが認証に HTTP Cookie のみを使用している場合、悪意のある Web サイトは脆弱なアプリケーションへの新しい WebSocket 接続をインスタンス化できるため、攻撃者はその接続を通じてデータの送受信の両方を行うことができます。

WebSocket 接続を使用したアプリケーションを確認す際は、常にこれを詳しく調べる価値があります。Gitpod サーバーに対する WebSocket リクエストを見てみましょう。

blog-websocket-takeover-gitpod.io-upgrade
blog-websocket-takeover-switching-protocols-feb-9

通常の状況では、接続は WebSocket に正常にアップグレードされ、通信が開始されます。WebSocket 交換自体内では追加の認証は行われず、WebSocket 接続を介して JSONRPC を呼び出すことができます。

blog-websocket-takeover-jsonrpc-2.0

今のところ、確立されたチャネル内で追加の認証が行われていることは確認されていません。これは、潜在的な攻撃者にとっては良い兆候です。では、確認したハンドシェイクを取得し、Origin ヘッダーを改ざんすることで、追加の Originチェックが行われていないことを確認しましょう。

blog-websocket-takeover-origin-workspace-id
blog-websocket-takeover-switching-protocols-feb-12

これは期待できそうです。ドメイン evil.com はクロスオリジン WebSocket リクエストを gitpod.io に発行できるように見えます。ただし、別のセキュリティメカニズムによって課題が生じます。

SameSite Cookie バイパス

SameSite Cookie は極めて最近追加されたものであり、クロスサイトリクエストフォージェリ (CSRF) 攻撃に対する部分的な軽減を提供します。すべての人がこれらを採用しているわけではありませんが、最も一般的なブラウザーでは、SameSite を明示的に無効にしないすべての Cookie のデフォルト値が Lax に設定されています。したがって、根源的な脆弱性は存在しますが、SameSite Cookie をバイパスしなければ、攻撃は主として理論上のものになり、時代遅れでニッチなブラウザーのサブセットに対してのみ機能します。

では、SameSite のコンテキストにおける site とは何でしょうか。簡単に言えば、site は、スキームと、オリジンのホストの登録可能なドメイン (存在する場合) の組み合わせに相当します。SameSite の仕様を見ると、サブドメインが考慮されていないことがわかります。これは、スキーム + ホスト (サブドメインを含む) + ポート (例: https://security.snyk.io:8443) で構成される、同一オリジンポリシーで使用されるオリジンの仕様よりも緩和されています。

blog-websocket-takeover-url-breakdown

先ほど、ワークスペースが gitpod.io のサブドメイン経由で公開されていることを確認しました。SameSite のコンテキストでは、ワークスペースの URL は gitpod.io と同じサイトであるとみなされます。したがって、1 つのワークスペースが、元のユーザーの Cookie を添付して、クロスドメイン SameSite リクエストを *.gitpod.io ドメインに発行できるはずです。攻撃者が制御するワークスペースを利用して WebSocket ハイジャックペイロードを提供できるかどうかを見てみましょう。 

まず、Cookie が実際に送信されて WebSocket 通信が正常に行われたことを確認するために、ワークスペースからブラウザーコンソールを開いて、WebSocket 接続の開始を試みます。

blog-websocket-takeover-gitpod-outline-cropped

上のスクリーンショットに示されているように、新しい WebSocket 接続を開くことを試みて、開いたら JSONRPC リクエストを送信します。コンソールの出力を見ると、リクエストの結果を含むメッセージが受信されています。これにより、Cookie が送信され、オリジンが gitpod.io への WebSocket を開くことが許可されていることを確認できます。

次に、Gitpod ユーザーがアクセスできるワークスペースから JavaScript を提供するための方法が必要です。利用可能な機能を調べると、ワークスペース内のポートを公開し、gitpod-cli と呼ばれるコマンドラインユーティリティを使用してそれらのポートにアクセス可能にすることができます。これは、gp と入力することでワークスペース内のパスで使用できます。gp ports expose 8080 を呼び出してから、python -m http.server 8080 を使用して基本的な Python Web サーバーをセットアップできます。これにより、下に示すように、公開されたポートにアクセスできる新しいサブドメインが作成されます。

blog-websocket-takeover-consol-error

ただし、接続は失敗しました。これは少し懸念すべきことであり、さらなる調査が必要です。ここで、ソースコードを開き、問題の原因となっている可能性のあるものを探します。次の正規表現パターンが見つかりました。これは、URL からワークスペース名を抽出するために使用されていると思われます。

blog-websocket-takeover-base-workspace-id

次のスクリーンショットに示すように、この照合が実行される方法が原因で、誤ったワークスペース名が抽出されます。

blog-websocket-takeover-test-string

そのため、Gitpod がホストするワークスペース内の公開ポートからコンテンツを提供することができないようなので、別の方法が必要です。現時点で、VS Code サービスを実行し、ワークスペース URL に発行されたリクエストを処理するマシンへの特権アクセスがあることはすでにわかっています。この特権アクセスを何らかの方法で悪用できるでしょうか。

当初のアイデアは、vscode プロセスを終了し、Python Web サーバーを起動して HTML ファイルを提供することでした。残念ながらこれはうまくいかず、ワークスペースが再起動される結果になりました。これは、ローカルサービス supervisor によって実行されたようです。このアプローチをテストしているときに気付いたことがあります。それは、別のプロセスを VS Code ポートにバインドせずにプロセスを終了すると、supervisor サービスが自動的に vscode プロセスを再起動し、その結果、ワークスペースが完全に再起動されずに UI が短時間ハングするということです。

これにより、期待できそうなアイデアが生まれました。VS Code にパッチを適用して、組み込みのエクスプロイトを提供することができるのではないかというアイデアです。

VS Code へのパッチ適用は比較的簡単です。元の VS Code サーバーのソースコードを配布バージョンと比較することで、エクスプロイトを提供するのに都合のよい場所をすぐに見つけられました。

VS Code には、/version に API エンドポイントが含まれており、これが現在のバージョンのコミットを返します。

blog-websocket-takeover-pathname-version

text/html の正しい Content-Type と HTML ファイルのコンテンツが返されるようにこれを変更しました。ここで、vscode プロセスを終了し、新たに導入した変更を、新たに生成された VS Code プロセスインスタンスに読み込めるようにしました。

blog-websocket-takeover-template-python

最後に、JSONRPC メソッドの getLoggedInUsergetGitpodTokensgetOwnerTokenaddSSHPublicKey を使用して、何の疑いも持たない Gitpod ユーザーがリンクにアクセスするとユーザーのワークスペースを完全に制御できるようになるペイロードを構築できます。

これが実際の動作です。

blog-websocket-takeover-pwnpod-info

ユーザーアカウントに関する機密情報を抽出できること、SSH キーがアカウントに追加された旨が通知されていることがわかります。ワークスペースへの SSH 接続ができるかどうかを確認してみましょう。

blog-websocket-takeover-task-list-redacted

成功です。上に示すように、送信したリンクにユーザーがアクセスすると、私たちはユーザーのワークスペースに完全にアクセスできるようになります。

タイムライン

  • 2023 年 2 月 13 日 (月) - ベンダーに脆弱性を開示

  • 2023 年 2 月 13 日 (月) - ベンダーが脆弱性を認める

  • 2023 年 2 月 14 日 (火) - 新バージョンがリリースされ、本番環境の SaaS Gitpod インスタンスにデプロイされる

  • 2023 年 2 月 22 日 (火) - CVE-2023-0957 が割り当てられる

  • 2023 年 3 月 1 日 (水) - ベンダーが Gitpod Self-Hosted の新バージョンをリリースし、勧告を発表

まとめ

この投稿では、クラウド開発環境 (CDE) に関する Snyk の最新調査の結果を発表しました。それは、リンクへのアクセス、一般的に誤解されている脆弱性 (WebSocket ハイジャック) の悪用、実質的な SameSite cookie バイパスの活用を通じて、アカウントが完全に乗っ取られるという結果でした。クラウド開発者ワークスペースの人気がますます高まっているため、もたらされる追加のリスクを考慮することが重要です。

Snyk は、このセキュリティ脆弱性への対処における Gitpod の素晴らしい方向転換に敬意を表します。また、近い将来、クラウドベースのリモート開発ソリューションに関するさらなる調査結果を発表できることに期待しています。