
Apache Spark 4.2.0 - Alto - Remoto - Privilegio residuo - mappa globale del processo Python Data Source
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-python-ds-static
Classe: Privilegio residuo Portata: Remota
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
DataSourceManager.dataSourceBuilders è una mappa JVM-globale first-wins. SPARK-45917 registra automaticamente le Python Data Source pyspark_* dal sys.path del worker di lookup. L'isolamento delle sessioni Connect mantiene gli artefatti sotto SparkFiles/<sessionUUID>/, e registerPython per sessione resta su runtimeDataSourceBuilders. Il primo lookup mette comunque la directory SparkFiles della sessione che lo attiva su sys.path, serializza (pickle) ogni DefaultSource e memorizza quelle classi nella companion object. Le successive query SQL Connect (o Hive Thrift SQL) read.format(name) / USING name eseguono quella classe come Spark UID senza inviare il proto Python.
Chi pianta è un tenant Python Connect a cui è già consentito Python. La vittima è un tenant solo-SQL sullo stesso driver Connect. Gli alias Java (parquet, csv, json, orc, jdbc) restano sul percorso Java ServiceLoader. I piantaggi successivi, dopo che la mappa è stata riempita, non si aggiornano. AC:H è il primo lookup più un nome che non è un alias Java.
| ID | nessuna CVE al momento |
| Classe | Privilegio residuo (Python Data Source cross-sessione come Spark UID; non invio di job non autenticato) |
| Portata | Remota (driver Spark Connect condiviso) |
| CWE | CWE-269, CWE-502 |
| CVSS | Alto: 8.8 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Prodotto | Apache Spark |
| Affetto | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) registro statico delle Python Data Source |
| Auth | Tenant Python Connect (chi pianta) più un successivo utente Connect solo-SQL / Hive Thrift SQL (vittima) |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1:18970. File testimone. Gadget della mappa companion. |
Mantenere una sessione Python Spark Connect su un driver condiviso. Pianta pyfiles/pyspark_<name>.py il cui DefaultSource.name() è un nome breve di connettore assente (delta, iceberg, hudi, ...). Attiva il primo lookup di Python Data Source su quella sessione. Ogni sessione successiva nella stessa JVM che esegue read.format(name) o SQL USING name istanzia la classe serializzata come Spark UID sul worker del planner del driver e sugli executor.
Questo è l'intero insieme di privilegi. Chi pianta esegue già Python. Il residuo è che un tenant solo-SQL, che non ha mai inviato il proto REGISTER_DATA_SOURCE / Python UDF, esegue comunque quella classe.
| Metodo | Sink | Privilegio |
|---|---|---|
Chi pianta: AddArtifacts nome pyfiles/pyspark_<name>.py poi primo format(name) / lookup | companion DataSourceManager.dataSourceBuilders (object DataSourceManager.scala) più lookup_data_sources.py iter_modules di pyspark_* | Memorizza il DefaultSource serializzato della sessione che lo attiva a livello JVM. Lab: layer='static' trigger='attacker' first-wins=yes. |
Vittima: SQL USING <name> / spark.read.format(name) su una sessione che non ha mai piantato | PythonDataSourceV2 createDataSourceInPython | Esegue quella classe come Spark UID. Lab: planted_by='attacker' witness_written=True static-cross-session=yes. Il file oracle contiene SPARK-PYTHON-DS-STATIC-WITNESS. |
| Metodo | Sink | Risultato |
|---|---|---|
| Piantaggio successivo di un secondo nome dopo che la mappa è stata riempita | stessa mappa statica | Chiuso. First-wins. Lab: later-lookup found=False, la companion contiene ancora solo delta. |
registerPython("alpha") per sessione | runtimeDataSourceBuilders | Isolato. Il clone copia solo il runtime. Lab: runtime-isolated=yes. La lettura di alpha da parte della vittima è found=False. |
Alias Java parquet | Java DataSourceRegister ServiceLoader | Chiuso. Lab: java-alias-closed=yes layer='java'. Idem per csv/json/orc/jdbc. |
| Metodo | Sink | Privilegio |
|---|---|---|
USING della vittima dopo il piantaggio | worker Python del driver + executor | Codice a livello di cluster come Spark UID. Il lab scrive un file testimone invece di un payload. |
| Stesso percorso | crash / spin del worker | Disponibilità come Spark UID. Non è l'Alto. L'Alto è l'esecuzione di codice. |
Hive Thrift SQL USING su una SparkSession condivisa | stessa mappa statica | Stesso residuo se Thrift e Connect condividono la JVM del driver. Non esercitato. |
parquet / csv / json / orc / jdbc Java. Vince il ServiceLoader.concatenatePaths rifiuta .. e nomi assoluti).pythonExec fornito dal client. Il planner Connect usa PYSPARK_PYTHON / python3 del server.registerPython. La mappa runtime è per istanza di DataSourceManager.pyspark locale mono-utente con una sola sessione. Non c'è altro tenant.Ho fissato apache/spark v4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8). Ventotto ricerche nel sorgente. L'invio di job che esegue codice utente è by design. History Jackson, la shell UI, l'impersonificazione locale di PySpark e il percorso di ricezione RPC standalone sono chiusi in questa analisi. Gli artefatti Connect isolano i pyfiles sotto un UUID di sessione. registerPython a runtime è per sessione. La companion object no.
SPARK-45917 registra automaticamente i pacchetti pyspark_* da PYTHONPATH. È previsto per i connettori installati dall'operatore. Il residuo è che il worker di lookup fa anche sys.path.insert della directory SparkFiles della sessione che lo attiva (worker_util.setup_spark_files), poi serializza qualunque DefaultSource pyspark_* trovi in una mappa globale di processo che non si aggiorna mai.
Falsa pista: considerare l'isolamento di registerPython come l'intera barriera tra tenant. Il runtime è isolato. Lo statico no.
cd lab
./run.sh
Loopback 127.0.0.1:18970. Progetto compose spark-python-ds-static. Testimone SPARK-PYTHON-DS-STATIC-WITNESS. Gadget Python di object DataSourceManager più mappe runtime per sessione. Pianta pyspark_delta.py solo negli SparkFiles dell'attaccante. Il lookup dell'attaccante riempie la companion. Il piantaggio successivo di iceberg non si aggiorna. La read di delta da parte della vittima scrive l'oracle. registerPython("alpha") non perde. Il parquet Java resta Java.
Ultima riga:
SUCCESS SPARK-PYTHON-DS-STATIC static-cross-session=yes runtime-isolated=yes first-wins=yes java-alias-closed=yes SPARK-PYTHON-DS-STATIC-WITNESS