
Apache Spark 4.2.0 - Alto - Remoto - Lettura di file - RPC StreamRequest File join non autenticato
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-rpc-stream-unauth
Classe: Residuo di privilegio / Lettura di file Raggiungibilità: Remota
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
CVE-2020-9480 ha chiuso RequestSubmitDriver / RegisterApplication non autenticati sul piano di controllo RPC. AbstractAuthRpcHandler protegge receive() e receiveStream(). Non protegge getStreamManager(). TransportRequestHandler continua a instradare StreamRequest su quel manager prima di SASL. NettyStreamManager.openStream esegue new File(dir, fname) senza alcun controllo di permanenza sotto la root.
StreamRequest non autenticato classes/../../path legge file Spark-UID. I figli assoluti Unix rimangono sotto la directory registrata (lab 404). files/ è una map get (404). receive() / receiveStream() rimangono 401. Questo non è l'RCE di 9480.
| ID | nessuna CVE al momento |
| Classe | Residuo di privilegio / Lettura di file (residuo non protetto del piano dati RPC di CVE-2020-9480) |
| Raggiungibilità | Remota (TCP non autenticato verso un driver RpcEnv / ESS / BlockManager con spark.authenticate=true) |
| CWE | CWE-862, CWE-22 |
| CVSS | Alto: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| Prodotto | Apache Spark |
| Affetto | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8). spark.authenticate=true abilitato dall'operatore. La lettura di file host richiede una directory registrata (spark.repl.class.outputDir /classes e/o artifacts di Connect). |
| Auth | nessuna su StreamRequest / getStreamManager() |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
TCP verso una porta RPC di Spark che ha spark.authenticate=true e una directory registrata. Nessun segreto condiviso. Nessun spark.network.crypto.enabled. Inviare un StreamRequest di trasporto (tipo messaggio 6) con streamId classes/../../<path>. TransportRequestHandler.processStreamRequest non chiama mai RpcHandler.receive. Chiama getStreamManager().openStream. Il wrapper di 9480 restituisce il manager reale. new File(dir, "../../oracle/secret") viene canonicalizzato al di fuori della root REPL/artifact e ritorna come FileSegmentManagedBuffer.
Questa è una lettura di file host con l'UID di Spark. Non è invio di job. Non è RequestSubmitDriver. Non è una shell.
| Metodo | Sink | Privilegio |
|---|---|---|
StreamRequest non autenticato classes/../../<path> | NettyStreamManager.openStream new File(dir, fname) poi FileSegmentManagedBuffer | Legge file con UID di Spark che il driver può aprire. Dimostrato in lab: opened /opt/repl-classes/../../oracle/secret, canonico /oracle/secret, corpo SPARK-RPC-STREAM-UNAUTH-WITNESS, x-auth-gated=false, x-authenticated=false. |
StreamRequest non autenticato classes/hello.txt (controllo in-dir) | stessa join, rimane sotto la directory registrata | Legge un file che è effettivamente sotto /classes. Dimostrato in lab 200 IN-DIR-OK, nessun witness. Conferma che il file server funziona senza SASL anche per un nome contenuto. |
| Metodo | Sink | Privilegio |
|---|---|---|
ChunkFetchRequest / StreamRequest non autenticato di uno streamId ESS attivo | OneForOneStreamManager.getChunk / openStream. checkAuthorization salta quando client.getClientId() == null | Legge byte di shuffle / disk-RDD in-flight di un'altra applicazione. Disponibilità: il drain avanza curChunk. Richiede uno streamId attivo (partenza casuale, poi +1). Il gadget non parlava con ESS attivo. |
MergedBlockMetaRequest non autenticato | AbstractAuthRpcHandler.getMergedBlockMetaReqHandler() anch'esso non protetto | Legge i bitmap dei chunk di merged-shuffle per un appId scelto quando ESS ha merged shuffle. Stesso salto con clientId nullo. Non esercitato. |
| Metodo | Sink | Rimane chiuso |
|---|---|---|
StreamRequest non autenticato classes//oracle/secret (figlio assoluto Unix) | new File(dir, "/oracle/secret") | 404. Il percorso aperto è /opt/repl-classes/oracle/secret. File di Unix concatena; non ignora il genitore. L'affermazione della caccia secondo cui un figlio assoluto elimina la root è errata su Unix. |
StreamRequest non autenticato files//oracle/secret | map get files | 404. files/ e jars/ sono ricerche per basename, non join. |
receive() / OneWayMessage non autenticato | AbstractAuthRpcHandler.receive | 401 Unauthenticated call to receive(). x-auth-gated=true. |
receiveStream() / UploadStream non autenticato | AbstractAuthRpcHandler.receiveStream | 401 Unauthenticated call to receiveStream(). |
receiveStream() autenticato con il segreto del lab | stesso gate dopo doAuthChallenge | 200 receiveStream-ok. Controllo che il segreto apre ancora il percorso 9480. |
Dimostrato in lab vs inferito: lettura di file con .. non autenticata, 404 su assoluto Unix, 404 su files/, receive / receiveStream protetti sono da lab. Il drain di shuffle ESS è inferito.
Adiacenti chiusi (non gonfiare):
RequestSubmitDriver / RegisterApplication non autenticati via OneWayMessage / UploadStream / RpcRequest. Richiede ancora il segreto condiviso.spark.authenticate=false predefinito (FAQ di SECURITY.md, default documentato di rete fidata). Non è questo residuo.AppIsolationSuite / SPARK-57889 con clientId non nullo)./classes o artifacts registrati, quindi questo percorso di file host è driver / REPL / Connect, non master:7077.spark.authenticate.secret.Ho fissato apache/spark v4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8), non master e non una RC 4.3. Ventotto ricerche nel sorgente. L'invio di job su un cluster aperto è by design. Il caricamento di modelli ML è codice eseguibile. L'RCE pubblico di Jackson History, la shell id -Gn della UI, l'impersonificazione locale di PySpark e il percorso receive di 9480 sono chiusi su questa peel.