This blog was co-authored by Elia Florio, Sr. Director of Detection & Response at Databricks and Florian Roth and Marius Bartholdy, security researchers with SEC Consult.
Original : Securing Databricks cluster init scripts
Databricksプラットフォームを保護し、セキュリティの改善で継続的にレベルを上げることは、私たちセキュリティチームの使命であり、バグバウンティプログラムに投資する主な理由です。このプログラムを通じて、私たちは、潜在的な懸念事項を私たちに知らせてくれ る有能な業界の専門家からの提出を奨励し(そして報酬を与え)ます。より大きなセキュリティコミュニティと協力することで、新たに発見された製品の問題を発見し、修正することができ、Databricksプラットフォームをより安全で安心な場所にすることができます。
また、バグバウンティプログラムで得られた協力関係の成功事例も、セキュリティコミュニティにとって興味深いものであれば、ご紹介しています。本日は、SEC Consulの優れたレポートが、非推奨のレガシー機能の廃止と新機能であるワークスペース・ファイルの採用を加速させたことを紹介したいと思います。
このブログは、DatabricksとSEC Consultがそれぞれ執筆した別々のセクションで構成されています。このブログでは、発見されたセキュリティ上の問題点、影響を受ける構成、影響、脆弱性に対処するために実施されたソリューションについて、技術的な詳細を説明しています。SEC Consultのプロフェッショナリズムとこの情報開示に対する協力に感謝します。
Intro
2023年1月末、DatabricksはSEC Consultから、クラスタの認証済み低特権ユーザーが、同じワークスペースおよび組織の境界内にある他のクラスタに対して特権を昇格し管理者 レベルのアクセスを得ることができる可能性がある特権昇格問題についての報告を受けました。
この問題を利用するには、(a)攻撃者が有効な認証済みアカウントを所有していること、(b)該当するワークスペースにおいて、レガシーなクラスタ用グローバルinitスクリプトが有効になっているか、代わりにDBFSに保存された設定済みのinitスクリプト(クラスタ名またはクラスタスコープ)が存在することが必要であることが、発見者のレポートと一致することからわかりました。DBFSに保存されたクラスタ用initスクリプトの場合、スクリプトが存在する場合にのみ脆弱性が悪用されるのとは対照的に、(スクリプトファイルがない)レガシーなグローバルinitスクリプトを有効にするだけで、この問題にさらされることになります。
どちらの場合も(レガシーグローバルinitスクリプトが有効、またはDBFSに保存されたクラスタinitスクリプト)、認証された低特権ユーザーがinitスクリプトを追加または制御し、initスクリプトの実行に伴う昇格特権を使用して追加コマンドを実行できる。Databricksは、このような特権の昇格が実際に発生した証拠を発見していません。
レガシーグローバルイニットスクリプトは、3年近く前にすでに非推奨となり、お客様は製品のUI(AWS | Azure)にあるトグルを切り替えるだけで、そのレガシースクリプトを無効化することができます。
次の表は、さまざまなタイプのinitスクリプトについて、最も一般的なシナリオをまとめたものです。(AWS | Azure | GCP):
Init script type |
Applicable cloud |
Vulnerability status |
Previously deprecated |
Legacy Global |
AWS, Azure |
Vulnerable |
Yes |
Cluster-named |
AWS, Azure |
Vulnerable |
Yes |
Global |
AWS, Azure, GCP |
Not Vulnerable |
No |
Cluster-scoped |
AWS, Azure, GCP |
Vulnerable |
No |
Cluster-scoped |
AWS, Azure, GCP |
Not Vulnerable |
No |
Cluster-scoped |
AWS, Azure, GCP |
Not Vulnerable |
No |
このSEC Consultからの報告を受けて、私たちは、一連の追加ステップと新しい製品機能によって、私たちのプラットフォームを強化し、お客様の安全を確保する機会を得ました:
- 非推奨のinitスクリプトタイプ(レガシーグローバルinitスクリプトとクラスタネームスクリプト)を使用した新しいワークスペースの作成を直ちに無効にしました;
- すべての非推奨initスクリプトタイプについて、厳格な使用終了期限(2023年9月1日)を発表し、より安全な代替手段への移行をさらに加速させました;
- 非推奨のinitスクリプトの無効化に従わなかったお客様には、レガシーなグローバルinitスクリプトとクラスターネー ムのinitスクリプトの両方でプロセスを自動化するツールを提供し、より安全な選択肢への移行を支援しました;
- 製品チームとエンジニアリングチームは、クラスタスコープのinitスクリプトをワークスペースファイル(AWS | Azure | GCP)に保存するためのサポートを追加し、最近一般的に利用できるようになったより安全な選択肢としました。また、製品UIにおけるクラスタスコープ付きinitスクリプトのデフォルトの場所をワークスペースファイルに変更し、initスクリプトの保存にDBFSを使用しようとするユーザーに対する可視メッセージを追加しました。
ワークスペースにおけるファイルのサポートにより、DatabricksユーザーはPythonソースコード、リファレンスデータセット、その他あらゆるタイプのファイルコンテンツ(initスクリプトを含む)をノートブック(AWS | Azure | GCP)と一緒に直接保存することができます。ワークスペース・ファイルは、ユーザーがバージョン管理システムを使用していない場合でも、プラットフォーム全体を通してDatabricks Reposで利用可能だった機能を拡張します。また、ワークスペース・ファイルでは、そのオブジェクトのアクセス制御リスト(ACL)を使用して、個々のファイルやフォルダへのアクセスを保護することができます(AWS | Azure | GCP)が、ユーザーやグループへのアクセスを制限するように構成することができます。
ガイダンスと推奨事項
私たちは過去3年間、レガシーで非推奨のinitスクリプトからの移行をお客様に勧めてきましたが、最近SEC Consultが報告したこのセキュリティの発見は、お客様ができるだけ早くこの移行の旅を完了すべき理由を強調するものです。同時に、initスクリプト(AWS|Azure|GCP)用のワークスペース・ファイルの導入は、DBFSに代わるより安全でモダンなストレージを提供する計画の最初のマイルストーンとなるものです。
お客様は、以下を行うことで、Databricksのデプロイメントのセキュリティを高め、本ブログで取り上げたセキュリティ問題を緩和することができます:
- レガシーグローバルインチスクリプト(AWS | Azure)を積極的に使用していない場合は、直ちに無効化する:これは、この潜在的な攻撃ベクトルを閉じるための安全、簡単、かつ即時のステップです。
- レ ガシーグローバルinitスクリプトを導入しているお客様は、まずレガシースクリプトを新しいグローバルinitスクリプトタイプに移行し(このノートブックを使用して移行作業を自動化できます)、この移行手順の後、前の手順で示したようにレガシーバージョンを無効化するよう進めてください。
- このタイプのinitスクリプトを使用しているお客様は、cluster-named init scriptsを無効にし(AWS | Azure)、cluster-scoped scriptsに移行し、スクリプトが新しいワークスペースファイルストレージの場所に保存されていることを確認してください(AWS | Azure | GCP)。このノートブックは、移行作業を自動化するために使用することができます。
- DBFSに保存 されている既存のクラスタスコープ付きinitスクリプトは、代替の安全なワークスペースファイルの場所(AWS | Azure | GCP)に移行する必要があります。
- Databricks Security Analysis Tool (SAT) を使用して、Databricksのセキュリティベストプラクティスに対するDatabricksワークスペース構成のセキュリティヘルスチェックを自動化します。
以下のセクションは、SEC Consultの研究員であるFlorian RothとMarius Bartholdyが執筆した技術報告書の内容を再現しています。以下の研究は、Azure Databricksを例として実施され、テストされましたが、非推奨のinitスクリプトの種類に関連する調査結果は、上記の表に示されるように、他のクラウドプロバイダーにも影響します。
SEC Consult、そしてDatabricksを日々より安全なものにするために私たちと協力してくれているセキュリティ研究者の皆様に改めて感謝いたします。もしあなたがセキュリティ研究者なら、hackerone.com/databricksでお会いすることになるでしょう。
Databricksのinitス クリプトのセキュリティについて研究しています
By Florian Roth and Marius Bartholdy, SEC Consult
低特権ユーザーが、同じワークスペースと組織の境界内にあるDatabricksコンピュートクラスタ間の分離を解除し、リモートでコードを実行することができました。その後、攻撃者はワークスペース内のすべてのファイルとシークレットにアクセスできるようになり、さらにワークスペース管理者の権限にエスカレートすることができました。
Databricks File System (DBFS) は、ワークスペース内のすべてのユーザが完全にアクセス可能です。DBFSには、Cluster-scopedおよびレガシーグローバルinitスクリプトも保存されているため、デフォルトのパーミッションを持つ認証済みの攻撃者は、以下のことが可能でした:
-
既存のクラスタ・スコープ付きinitスクリプトを検索して修正します
-
レガシーなグローバルinitスクリプトのデフォルトの場所に新しいスクリプトを配置します
非推奨のinitスクリプトタイプ(レガシーグローバルやクラスタネームなど)を提供するためのデフォルトのオプションは、それらをDBFSにアップロードすることでした。DBFSは同じワークスペース内のすべての計算クラスタ間で共有されているため、以前にクラスタで構成されDBFSに保存されていた既存のinitスクリプトを見つけるか推測することが可能でした。こ れは、既存のDBFSディレクトリの内容をリストアップすることで実現可能です:
display(dbutils.fs.ls("dbfs:/databricks/scripts"))
見つかった.shファイルはすべてクラスタスコープのinitスクリプトである可能性があるため、何らかの方法で置き換えることが目標でした。ファイルを直接上書きすることはできませんが、以下のコードでファイル名を変更し、古い名前の新しいスクリプトを作成することができました。この新しい悪意のあるスクリプトには、定期的に起動するシンプルなリバースシェルが含まれています。クラスタ構成はスクリプト名しか認識していなかったため、initスクリプトが再びトリガーされるとすぐに、コンピュートクラスタのroot権限を持つリバースシェルが受信されました:
シークレットは、マネージドIDを介してコンピュートインスタンス自身によってのみ実行時に取得することができます。ワークスペース管理者でも読むことはできません。しかし、計算クラスタが初期化されると同時に利用可能になるため、その平文値を取得することは可能でした。Sparkの設定の秘密は/tmp/custom-spark.confにあり、環境変数の秘密は正しいプロセスの/proc/<process-id>/environファイルを読み込むことでアクセスできます。
Secureworks 社のJoosua Santasalo が最初に発見した脆弱性を利用すると、同じインスタンスで操作している場合、管理者を含む他のユーザーのDatabricks APIトークンを漏洩することが可能です。当初の発見では、ユーザーを互いに隔離し、特に管理者から隔離することで改善されました。しかし、今回の脆弱性では、攻撃者が制御するスクリプトを実行することで隔離を解除することができ、結果として古いエクスプロイトが再び有効になりました。
以前に確立したリバースシェルを使って、制御プレーンのトラフィックをキャプチャすることが可能でした。管理者ユーザーでタスクを開始すると、例えば簡単なノートブックを実行すると、トークンが暗号化されずに送信され、漏えいする可能性がありました:
取得したトークンは、Databricks REST APIへのリクエストを認証するために使用することができます。以下の例では、シークレットスコープの閲覧が可能なため、トークンが管理者権限を持っていることが確認できました:
2) レガシーなグローバルinitスクリプトを使用したアタックチェーン
同じ攻撃ベクトルは、レガシーなグローバルinitスクリプトに影響を与えました。これらは2020年に非推奨となりましたが、すべてのワークスペースでデフォルトで有効なまま、DBFS上、特にdbfs:/databricks/init/に保存されていました。どのクラスタでも、初期化時にその内容を実行するようになっていました。したがって、そのディレクトリに新しいスクリプトを作成するだけで、最終的にはすべてのクラスタでコードが実行されることになります。