
Apache Tomcat 11.0.27 — высокий — удалённый — DoS — RewriteValve [NS] worker pin
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · tomcat-rewrite-ns-loop
Класс: DoS Доступ: Удалённый
Apache Tomcat 11.0.27 (52f3b364) - tomcat.apache.org
RewriteValve.parseRuleFlag выполняет сопоставление по префиксу. После NC/NE любой оставшийся флаг, который startsWith("N"), включает next. Скопированные из httpd [NS] (nosubreq) и [NV] (novary) превращаются в [N]. Подстановка - оставляет substitution равным null; затем RewriteRule.evaluate возвращает исходный URL. isNext() вместе с ненулевым newtest устанавливает i = -1 без ограничения на число раундов, поэтому один неаутентифицированный GET, соответствующий правилу, удерживает поток HTTP-коннектора до тех пор, пока клиент не отключится или процесс не будет перезапущен. Явные [N] и [S=-1] дают такое же удержание. [L,NS] безопасен, поскольку isLast() срабатывает первым.
CVE-2026-65927 (Important, 11.0.25) исправил перезапуск [N] со второго правила. У этого удержания по-прежнему нет ограничения на число раундов. В тот же день в main после 11.0.27 добавили MAX_REWRITE_ROUNDS=1000 и точное сопоставление флагов (2da9fddb, 8992dbdd) без security-рекомендации.
| ID | CVE пока нет |
| Класс | DoS |
| Доступ | Удалённый (неаутентифицированный HTTP) |
| CWE | CWE-835 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| Продукт | Apache Tomcat |
| Затронуто | 11.0.27 (52f3b364e5882a5dbcfc42cb8313a7c2ae532c64) RewriteValve |
| Аутентификация | неаутентифицированный HTTP |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Я зафиксировал тег 11.0.27 и изучил RewriteValve.invoke. Этот valve отсутствует в стандартном conf/server.xml. Путь по умолчанию для Host — conf/Catalina/localhost/rewrite.config. Лаборатория — loopback HTTP на 127.0.0.1:18910. Официальный tarball 11.0.27. Не RCE.
| Метод | Точка срабатывания | Привилегия |
|---|---|---|
Неаутентифицированный GET /loop, соответствующий правилу Host rewrite.config RewriteRule ^/loop$ - [NS] | RewriteValve.invoke i = -1, поскольку startsWith("N") для токена NS | Доступность (подтверждено в лаборатории): удержание одного потока HTTP-коннектора до тех пор, пока клиент не отключится или процесс не будет перезапущен. Лаборатория: /loop завершился по таймауту через 4.002 с. |
Неаутентифицированный GET /next с явным [N] | тот же перезапуск isNext() | Доступность (подтверждено в лаборатории): такое же удержание. Лаборатория: /next завершился по таймауту через 4.003 с. |
Неаутентифицированный GET /skip с [S=-1] | i += -1, затем инкремент for | Доступность (подтверждено в лаборатории): такое же удержание. Лаборатория: /skip завершился по таймауту через 4.002 с. |
| Один соответствующий запрос на worker | та же точка срабатывания, maxThreads одновременных соответствующих URL | Доступность (предположительно): заполнение пула коннектора (в лаборатории использовалось 32; стандартное значение по умолчанию — 200). Новые запросы затем ставятся в очередь или отклоняются. Соседний /ok всё ещё отвечал, пока один /loop был в обработке. |
Зависание против 404 за 13 мс на /ok | тайминг next/skip против [L] | Разведка (подтверждено в лаборатории): позволяет определить, что сработало правило next/skip. Лаборатория: зависание 4.002 с против 404 за 0.013 с. |
Подтверждено в лаборатории против предположительного: зависание /loop [NS], зависание /next [N], зависание /skip [S=-1], /ok [L] 404 за 13 мс, /safe [L,NS] 404 за 5 мс и соседний /ok 404, пока /loop в обработке, — подтверждены в лаборатории. Истощение пула предполагается исходя из удержания одного потока плюс maxThreads.
Требуется: RewriteValve на Host или Context и соответствующее правило в rewrite.config. Valve включается опционально, того же класса, что и закомментированный AJP. Скопированный из httpd [NS] — это соответствующее правило, а не намеренный бесконечный цикл [N].
| Поверхность | Лаборатория |
|---|---|
[L,NS] (httpd last+nosubreq) | /safe 404 за 5 мс (L-ns-safe=yes) |
| Другие запросы в обработке, пока один поток удержан | /ok 404 за 13 мс во время /loop (sibling-alive=yes) |
Стандартный server.xml без RewriteValve | valve отсутствует; остаточный код не срабатывает |
| RCE / чтение WEB-INF / обход ограничений CVE-2026-65927 | [N] теперь перезапускается с правила 0; этот остаток влияет только на доступность |
| Manager / JMX / AJP / DefaultServlet PUT | без изменений; PUT по-прежнему readonly |
Никакого выполнения кода от имени пользователя Tomcat. Никакого чтения conf/ или WEB-INF. Никакого перехвата сессии. Никакого развёртывания через Manager. JVM продолжает работать; другие worker'ы всё ещё отвечают, пока пул не заполнен.
cd lab
./run.sh
Loopback 127.0.0.1:18910 сопоставляется с контейнером 8080. Compose-проект tomcat-rewrite-ns-loop. Тег образа tomcat-rewrite-ns-loop:11.0.27. Официальный apache-tomcat-11.0.27.tar.gz SHA512 a617896307cada4884b24f80c4e977ddad8b3e0f88ce0e2a6eea29d5f332498e276ae5976c227a9c8daecf05c7c90def684a3766dd5a81f47a56d8b1adf43dc3. Свидетельство TOMCAT-REWRITE-NS-LOOP-WITNESS. Последняя строка:
SUCCESS TOMCAT-REWRITE-NS-LOOP control-ok=yes ns-hang=yes L-ns-safe=yes n-hang=yes skip-hang=yes sibling-alive=yes TOMCAT-REWRITE-NS-LOOP-WITNESS
rewrite.config лаборатории:
RewriteRule ^/loop$ - [NS]
RewriteRule ^/next$ - [N]
RewriteRule ^/skip$ - [S=-1]
RewriteRule ^/ok$ - [L]
RewriteRule ^/safe$ - [L,NS]
Ограничить число раундов перезаписи (MAX_REWRITE_ROUNDS=1000 в main после этого тега, коммит 2da9fddb). Точное сопоставление флагов, чтобы [NS] не проходил парсинг (коммит 8992dbdd). Отклонять skip < 0. Пока это не попадёт в релиз: избегайте [NS]/[NV]/[N]/[S=-1] в соответствующих правилах или откажитесь от RewriteValve.