
Apache Spark 4.2.0 - Hoch - Remote - Privilegien-Reste - prozessglobale Python-Datenquellen-Zuordnung
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-python-ds-static
Klasse: Privilegien-Überrest Reichweite: Remote
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
DataSourceManager.dataSourceBuilders ist eine JVM-globale First-Wins-Map. SPARK-45917 registriert pyspark_* Python Data Sources automatisch aus dem sys.path des Lookup-Workers. Die Connect-Session-Isolierung hält Artefakte unter SparkFiles/<sessionUUID>/, und das sitzungsbezogene registerPython bleibt auf runtimeDataSourceBuilders. Der erste Lookup legt dennoch das SparkFiles-Verzeichnis der auslösenden Session auf sys.path, pickelt jedes DefaultSource und cached diese Klassen im Companion-Objekt. Späteres Connect-SQL (oder Hive-Thrift-SQL) read.format(name) / USING name führt diese Klasse als Spark-UID aus, ohne Python-Proto zu senden.
Der Pflanzer ist ein Connect-Python-Mandant, dem Python bereits erlaubt ist. Das Opfer ist ein reiner SQL-Mandant auf demselben Connect-Treiber. Java-Aliase (parquet, csv, json, orc, jdbc) bleiben auf dem Java-ServiceLoader-Pfad. Spätere Pflanzungen, nachdem die Map gefüllt ist, aktualisieren nicht. AC:H ist First-Lookup plus ein Name, der kein Java-Alias ist.
| ID | noch keine CVE |
| Klasse | Privilegien-Überrest (Cross-Session Python Data Source als Spark-UID; kein Unauth-Job-Submit) |
| Reichweite | Remote (gemeinsamer Spark-Connect-Treiber) |
| CWE | CWE-269, CWE-502 |
| CVSS | High: 8.8 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Produkt | Apache Spark |
| Betroffen | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) Python Data Source Static Registry |
| Auth | Connect-Python-Mandant (Pflanzer) plus ein späterer reiner SQL-Connect-/Hive-Thrift-SQL-Benutzer (Opfer) |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1:18970. Witness-Datei. Gadget der Companion-Map. |
Eine Spark-Connect-Python-Session auf einem gemeinsamen Treiber halten. pyfiles/pyspark_<name>.py pflanzen, dessen DefaultSource.name() ein nicht vorhandener Connector-Kurzname ist (delta, iceberg, hudi, ...). Den ersten Python-Data-Source-Lookup in dieser Session auslösen. Jede spätere Session in derselben JVM, die read.format(name) oder SQL USING name ausführt, instanziiert die gepickelte Klasse als Spark-UID im Driver-Planner-Worker und auf den Executors.
Das ist die vollständige Privilegienmenge. Der Pflanzer führt bereits Python aus. Der Überrest besteht darin, dass ein reiner SQL-Mandant, der nie REGISTER_DATA_SOURCE / Python-UDF-Proto gesendet hat, diese Klasse dennoch ausführt.
| Methode | Sink | Privileg |
|---|---|---|
Pflanzer: AddArtifacts Name pyfiles/pyspark_<name>.py, dann erstes format(name) / Lookup | Companion DataSourceManager.dataSourceBuilders (DataSourceManager.scala-Objekt) plus lookup_data_sources.py iter_modules von pyspark_* | Das gepickelte DefaultSource der auslösenden Session JVM-weit cachen. Lab: layer='static' trigger='attacker' first-wins=yes. |
Opfer: SQL USING <name> / spark.read.format(name) in einer Session, die nie gepflanzt hat | PythonDataSourceV2 createDataSourceInPython | Diese Klasse als Spark-UID ausführen. Lab: planted_by='attacker' witness_written=True static-cross-session=yes. Oracle-Datei enthält SPARK-PYTHON-DS-STATIC-WITNESS. |
| Methode | Sink | Ergebnis |
|---|---|---|
| Spätere Pflanzung eines zweiten Namens, nachdem die Map gefüllt ist | dieselbe statische Map | Geschlossen. First-Wins. Lab: later-lookup found=False, Companion weiterhin nur delta. |
Sitzungsbezogenes registerPython("alpha") | runtimeDataSourceBuilders | Isoliert. Clone kopiert nur Runtime. Lab: runtime-isolated=yes. Opfer-Lesen von alpha ist found=False. |
Java-Alias parquet | Java DataSourceRegister ServiceLoader | Geschlossen. Lab: java-alias-closed=yes layer='java'. Dasselbe für csv/json/orc/jdbc. |
| Methode | Sink | Privileg |
|---|---|---|
Opfer USING nach Pflanzung | Driver- + Executor-Python-Worker | Cluster-weiter Code als Spark-UID. Das Lab schreibt eine Witness-Datei statt einer Payload. |
| Derselbe Pfad | Worker-Absturz / Spin | Verfügbarkeit als Spark-UID. Nicht das High. Das High ist die Codeausführung. |
Hive-Thrift-SQL USING auf einer gemeinsamen SparkSession | dieselbe statische Map | Derselbe Überrest, wenn Thrift und Connect dieselbe Driver-JVM teilen. Nicht getestet. |
parquet / csv / json / orc / jdbc-Hijack. ServiceLoader gewinnt.concatenatePaths lehnt .. und absolute Namen ab).pythonExec. Connect-Planner verwendet Server-PYSPARK_PYTHON / python3.registerPython. Runtime-Map ist pro DataSourceManager-Instanz.pyspark mit einer Session. Es gibt keinen anderen Mandanten.Ich habe apache/spark v4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) gepinnt. Achtundzwanzig Source-Hunts. Job-Submit, der Benutzercode ausführt, ist by Design. History Jackson, UI-Shell, PySpark-lokale Impersonation und der Standalone-RPC-Receive-Path sind in diesem Peel geschlossen. Connect-Artefakte isolieren pyfiles unter einer Session-UUID. Runtime-registerPython ist pro Session. Das Companion-Objekt nicht.
SPARK-45917 registriert pyspark_*-Pakete automatisch aus PYTHONPATH. Das ist für operator-installierte Connectoren gedacht. Der Überrest besteht darin, dass der Lookup-Worker außerdem das SparkFiles-Verzeichnis der auslösenden Session per sys.path.insert einfügt (worker_util.setup_spark_files) und dann jedes gefundene pyspark_* DefaultSource in eine prozessglobale Map pickelt, die nie aktualisiert wird.
Fehlweg: die registerPython-Isolierung als die gesamte Mandantenschranke zu betrachten. Runtime ist isoliert. Static nicht.
cd lab
./run.sh
Loopback 127.0.0.1:18970. Compose-Projekt spark-python-ds-static. Witness SPARK-PYTHON-DS-STATIC-WITNESS. Python-Gadget von object DataSourceManager plus sitzungsbezogene Runtime-Maps. pyspark_delta.py nur in den SparkFiles des Angreifers pflanzen. Angreifer-Lookup füllt den Companion. Spätere Pflanzung von iceberg aktualisiert nicht. Opfer-read von delta schreibt das Oracle. registerPython("alpha") leakt nicht. Java-parquet bleibt Java.
Letzte Zeile:
SUCCESS SPARK-PYTHON-DS-STATIC static-cross-session=yes runtime-isolated=yes first-wins=yes java-alias-closed=yes SPARK-PYTHON-DS-STATIC-WITNESS