Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
spark-history-store-path — Apache Spark 4.2.0 - Élevé - À distance - Écriture de fichier - History appStorePath App ID non assaini | Kitploit
Outils/GitHubGitHub/abraxas/spark-history-store-path
Analyse StatiqueAnalyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionLabs et Pratique
GitHubabraxas/spark-history-store-path

spark-history-store-path

Apache Spark 4.2.0 - Élevé - À distance - Écriture de fichier - History appStorePath App ID non assaini

Voir le dépôt
il y a 2 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Abraxas Labs - spark-history-store-path

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  spark-history-store-path

spark-history-store-path

Classe : Écriture de fichier (conditionnée par la configuration) Portée : Distante

Apache Spark 4.2.0 (32f72996) - Apache Software Foundation

HistoryServerDiskManager.appStorePath effectue new File(appStoreDir, appId + extension) sans assainissement. Utils.sanitizeDirName ne concerne que les noms de fichiers du journal d'événements. Le champ JSON App ID est traité via asText(). Le listing stocke event.appId.orNull. Lease.commit utilise cette chaîne. Un App ID ../ écrit un .rdb en dehors de spark.history.store.path. Par défaut, store.path non défini est en mémoire (aucune écriture). Le contenu est un fichier de stockage, pas une RCE.

IDpas encore de CVE
ClasseÉcriture de fichier (stockage disque History conditionné par la configuration)
PortéeDistante (écrivain du journal d'événements plus History avec spark.history.store.path défini ; ACLs de l'UI désactivées par défaut)
CWECWE-22
CVSSÉlevé : 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N lorsque spark.history.store.path est défini
ProduitApache Spark History Server
Affecté4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8)
Authécrivain de spark.history.fs.logDirectory (par défaut file:/tmp/spark-events) ; History doit avoir spark.history.store.path défini
LicenceGNU Affero GPL v3.0
Lab127.0.0.1:18990 uniquement. Gadget de la jointure citée. Témoin .rdb en dehors de store.path.

Ce qu'un attaquant peut faire

Même modèle de victime que CVE-2025-54920 : History Server pointé vers un répertoire de journaux dans lequel l'attaquant peut écrire. Jackson ne construit plus de gadgets de classe HiveConnection. Le chemin du stockage disque fait toujours confiance à l'App ID du JSON d'événement.

MéthodePoint de chutePrivilègeLab vs déduit
Placer un journal d'événements dont le JSON App ID est ../<name> (ou ../../oracle/...). Attendre le scan. GET qui charge l'UI de l'app / getAppUI / loadDiskStore / createDiskStoreHistoryServerDiskManager.appStorePath puis Lease.commit renameToIntégrité : créer un chemin .rdb (RocksDB par défaut) ou .ldb (LevelDB) en dehors de {store.path}/apps en tant qu'UID History. Prouvé en lab sur le gadget : escaped=yes, le fichier /work/oracle/SPARK-HISTORY-STORE-PATH-WITNESS.rdb contient le témoin. Le contenu est un fichier de stockage, pas du bytecode hôte choisi par l'attaquant, pas un shell.Prouvé en lab (écriture gadget des octets témoins au chemin échappé). Le renameTo complet de History d'un répertoire RocksDB est la même jointure.
Même App ID lorsque la destination échappée est déjà un répertoireLease.commit if (dst.isDirectory()) deleteStore(dst) puis Utils.deleteRecursivelyDisponibilité : supprimer un répertoire existant dont le nom se termine déjà par le suffixe du backend, puis le remplacer par le stockage loué.Déduit (épingler le commit de HistoryServerDiskManager.scala). Le gadget a écrit un fichier, n'a pas appelé deleteRecursively.
spark.history.store.path non défini par défautLOCAL_STORE_DIR createOptional ; diskManager = storePath.mapFermé. Listing en mémoire. Pas de HistoryServerDiskManager. Prouvé en lab gated=yes written=no.Prouvé en lab
Appliquer Utils.sanitizeDirName à l'App ID d'abordhelper de nom de fichier du journal d'événementsReste dans apps/. / et : deviennent -. Négatif prouvé en lab.Prouvé en lab
Contrôler l'App ID local-control avec store.path définimême jointureÉcrit {store.path}/apps/local-control.rdb. Reste dans apps/.Prouvé en lab

Fermé adjacent : store non défini par défaut (en mémoire). Jackson sparkEventFromJson requiert toujours SparkListenerEvent (CVE-2025-54920). Le fallback URL getAppUI eventlog_v2_ + nameForAppAndAttempt est assaini. La clé KV du listing n'est pas un chemin de système de fichiers. Le mapper HybridStore / kvstore n'a pas de Id.CLASS. History HTTP n'accepte pas de chemin d'upload. Compaction désactivée par défaut. Cleaner désactivé par défaut. Soumission de job sur un cluster ouvert (FAQ SECURITY.md). Chargement de modèle ML (docs/ml-security.md). Ce reliquat n'est pas une RCE hôte.

Comment je l'ai trouvé

J'ai épinglé Spark 4.2.0, pas master, pas une RC 4.3. Vingt-huit chasses. La RCE Jackson publique de History est fermée sur cette version. Les écrivains de journaux d'événements appellent déjà Utils.sanitizeDirName donc le fichier journal ne peut pas contenir /. Le nom du fichier de cache disque utilise l'App ID brut.

private[history] def appStorePath(appId: String, attemptId: Option[String]): File = {
  val fileName = appId + attemptId.map("_" + _).getOrElse("") + extension
  new File(appStoreDir, fileName)
}

appStoreDir est {spark.history.store.path}/apps. Sous Unix, new File(parent, "../../oracle/name.rdb") se résout en dehors du parent. JsonProtocol.applicationStartFromJson prend json.get("App ID").asText(). AppListingListener.onApplicationStart stocke event.appId.orNull. lease.commit(appId, attempt.info.attemptId) alimente cette chaîne vers appStorePath.

Fausses pistes déjà consignées : traiter store.path non défini par défaut comme une écriture (il est en mémoire) ; s'attendre à ce que new File(dir, "/abs") sous Unix ignore le parent (ce n'est pas le cas ; le reliquat est ..) ; prétendre à une RCE parce que le suffixe est .rdb ; démarrer un History Server complet alors que la jointure est l'oracle ; considérer que sanitizeDirName couvre ce chemin.

Lab

python3 spark-history-store-path-Abraxas-Labs.py

ou

cd lab
./run.sh

Gadget de HistoryServerDiskManager.appStorePath sur 127.0.0.1:18990. Extraits épinglés sous lab/pin/. Le History Server complet n'est pas démarré. Le lier à loopback.

SUCCESS SPARK-HISTORY-STORE-PATH how=gadget escaped=yes gated=yes outside=/work/oracle/SPARK-HISTORY-STORE-PATH-WITNESS.rdb SPARK-HISTORY-STORE-PATH-WITNESS

Le correctif

Exécuter Utils.sanitizeDirName (ou rejeter .. / / / NUL) sur appId et attemptId à l'intérieur de appStorePath avant new File. Après la jointure, exiger que dst.getCanonicalFile() reste sous appStoreDir.getCanonicalFile(). spark.history.store.path non défini reste la valeur par défaut sûre.

Références

Télécharger l’outil