Блог

NGINX Rift: 18-летний баг в rewrite-модуле и почему твой сервер под угрозой прямо сейчас.

NGINX_Rift
Linux

NGINX Rift: 18-летний баг в rewrite-модуле и почему твой сервер под угрозой прямо сейчас.

Представь: твой nginx работает уже несколько лет. HTTPS настроен, заголовки безопасности выставлены, fail2ban банит ботов. Ты закрыл все очевидные дыры. И тут кто-то присылает один-единственный HTTP-запрос — такой же как тысячи других — и твой воркер-процесс падает. Если ASLR у тебя выключен — они уже выполняют произвольный код от имени nginx.

Ничего не сломано снаружи. Nginx поднял новый воркер и продолжает работать. Никакого алерта. Просто в логах мелькнула строчка «worker process exited on signal 11».

Добро пожаловать в CVE-2026-42945, известный как NGINX Rift.

ОН БЫЛ ВЕЗДЕ — И НИКТО НЕ ЗАМЕЧАЛ

13 мая 2026 года F5 совместно с исследовательской платформой depthfirst раскрыли критическую уязвимость в ngx_http_rewrite_module. Это модуль, который отвечает за обработку директив rewrite, if и set — то есть за перезапись URL. Почти любой нетривиальный конфиг nginx его использует.

Уязвимость существует с 2008 года. С версии nginx 0.6.27. Это значит, что она сидела в исходниках через все версии, через все security-аудиты, через все обновления. 18 лет.

Затронуто: NGINX Open Source 0.6.27 — 1.30.0, NGINX Plus R32 — R36, и всё что собрано на том же ngx_http_script.c — включая Ingress NGINX в Kubernetes-кластерах.

CVSS v4.0: 9.2 Critical. CVSS v3.1: 8.1 High.

Интересная деталь про то как её нашли: depthfirst загрузил исходники nginx в свою AI-систему анализа кода и получил результат примерно за шесть часов. Шесть часов против восемнадцати лет. Это не упрёк в адрес nginx — это сигнал о том, что ручной code review больше не справляется с таким классом уязвимостей.

ЧТО ТАКОЕ HEAP BUFFER OVERFLOW И ПОЧЕМУ ЭТО ПЛОХО

Прежде чем разбирать конкретный баг — секунда на контекст, потому что этот термин важен.

Когда nginx обрабатывает запрос, он выделяет кусок памяти (heap) для работы с данными. Buffer overflow — это когда программа записывает данных больше, чем помещается в выделенный кусок, и начинает затирать соседнюю память. В этой соседней памяти могут находиться указатели на функции, управляющие структуры, что угодно.

Почему это критично: если атакующий может контролировать что именно записывается за границу буфера, он может перезаписать указатель на функцию своим адресом. Когда nginx вызовет эту функцию — выполнится код атакующего. Это и есть Remote Code Execution.

КАК РАБОТАЕТ БАГ

nginx обрабатывает rewrite-правила в два прохода по коду.

Первый проход — разведчик. Он проходит по правилу и считает: сколько байт нужно выделить под результирующую строку? Смотрит на паттерн, на replacement, на captures — формирует итоговый размер буфера.

Второй проход — исполнитель. Получает уже выделенный буфер нужного размера и копирует туда данные.

Проблема в одном флаге под названием is_args. Он выставляется на первом проходе, когда в строке замены встречается знак вопроса — это сигнал что дальше идёт query string, то есть параметры вида ?id=123. Логика правильная: флаг нужен чтобы первый проход корректно посчитал длину.

Но флаг не сбрасывается между проходами. Он просачивается во второй — и там заставляет функцию ngx_escape_uri работать в другом режиме, с другой логикой экранирования, с другим расчётом длины. В итоге второй проход пишет больше байт чем выделил первый. Буфер переполняется.

Срабатывает только при двух одновременных условиях:
— unnamed PCRE captures в правиле: $1, $2, $3 (это когда группа в regex без имени — просто круглые скобки)
— знак вопроса в строке замены

Пример — типичный API-прокси:

location /api/ {
    rewrite ^/api/(.*)$ /internal?id=$1 last;
}

Тут есть и unnamed capture (.*) — это $1 — и вопросительный знак перед id=$1. Оба условия выполнены. Этот конфиг уязвим.

И это не редкость. Это стандартный паттерн который встречается в половине туториалов по nginx. Авторы писали его корректно — они просто не знали, что внутри таится флаг который неправильно сбрасывается.

КАК ИМЕННО ЭКСПЛУАТИРУЕТСЯ

Атакующий отправляет HTTP-запрос на уязвимый endpoint. В URI — длинная строка из повторяющихся символов, например сотни знаков +.

Первый проход считает длину буфера исходя из нормальной логики — без учёта просочившегося флага. Буфер выделяется.

Второй проход начинает копировать — и из-за неправильного флага ngx_escape_uri начинает добавлять escape-последовательности (%2B вместо +, например). Строка растёт. Выходит за границу буфера. Затирает соседнюю память.

Критически важная деталь: данные которые пишутся за границу буфера — это URI из запроса атакующего. Он контролирует что именно туда попадает. Это не случайное затирание памяти мусором — это управляемая запись.

ЧТО ПРОИСХОДИТ ДАЛЬШЕ — ЗАВИСИТ ОТ НАСТРОЕК СИСТЕМЫ

С включённым ASLR (Address Space Layout Randomization, параметр kernel.randomize_va_space = 2):
При каждом запуске процесса адреса в памяти рандомизируются. Атакующий не знает где именно в памяти находится то что он хочет перезаписать. Переполнение происходит, но попадает в случайное место — nginx падает с signal 11 (segfault) и перезапускается. Это Denial of Service: неприятно, сайт моргает, но не катастрофа.

Без ASLR или с ASLR выключенным:
Адреса предсказуемы. Атакующий знает куда писать. Результат — детерминированный RCE: один запрос, произвольный код от имени nginx.

Но есть нюанс с ASLR: depthfirst задокументировал в своём PoC технику под названием progressive heap shaping. Это серия специально подобранных запросов, которые постепенно «укладывают» heap в нужную форму — так чтобы нужные структуры оказались в предсказуемых местах даже с ASLR. Это сложнее одного запроса, требует времени, но работает. То есть ASLR не абсолютная защита — он поднимает планку, но не закрывает дыру.

16 мая — через три дня после публикации PoC — VulnCheck зафиксировал первые реальные попытки эксплуатации в интернете.

ЦЕПОЧКА АТАКИ В РЕАЛЬНОМ МИРЕ

NGINX Rift особенно опасен не сам по себе, а в связке с другими майскими уязвимостями.

NGINX Rift даёт атакующему выполнение кода в контексте nginx-воркера — пользователь www-data или nginx, непривилегированный. Само по себе неприятно, но не root.

Dirty Frag (CVE-2026-43284 / CVE-2026-43500) — уязвимость ядра Linux, раскрытая в начале мая 2026. Позволяет любому непривилегированному пользователю получить root через переполнение page cache в модулях esp4/esp6/rxrpc.

Цепочка: один HTTP-запрос → foothold в nginx-воркер → Dirty Frag → root на сервере. Без аутентификации. Без учётных записей. Без следов в логах приложения.

Это не теоретическая атака. Патч для обоих нужен прямо сейчас.

ПРОВЕРИТЬ СЕБЯ — ТРИ КОМАНДЫ

Первое — версия nginx. Нужно 1.30.1 или выше:

nginx -v

Если видишь что-то вроде nginx/1.24.0 или nginx/1.18.0 — уязвим.

Второе — есть ли уязвимые правила в конфиге. Ищем rewrite-директивы с $1/$2 и вопросительным знаком:

grep -rn "rewrite" /etc/nginx/ | grep -E '\$[0-9].*\?'

Пустой вывод — хорошо. Непустой — у тебя уязвимая конфигурация, обновляйся немедленно независимо от версии nginx (будущий конфиг на новой версии будет безопасен, но проверить стоит).

Третье — ASLR. Пока не обновился, убедись что включён:

cat /proc/sys/kernel/randomize_va_space

Должно быть 2. Если 0 или 1 — это значит что RCE одним запросом. Включить немедленно:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
echo "kernel.randomize_va_space = 2" | sudo tee /etc/sysctl.d/99-aslr.conf
sudo sysctl -p /etc/sysctl.d/99-aslr.conf

Это не закрывает уязвимость — но переводит сценарий с RCE на DoS. Значительно лучше.

ОБНОВЛЕНИЕ

Обновление — единственное полное решение. Конфигурационных воркараундов недостаточно для production.

Debian/Ubuntu:

sudo apt update && sudo apt install nginx
nginx -v

Важный момент: официальные репозитории Ubuntu и Debian иногда отстают на несколько дней от upstream. Если apt выдаёт версию ниже 1.30.1 — подключи официальный репозиторий nginx.org напрямую. Это безопасно: ключи GPG верифицированы.

curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list

sudo apt update && sudo apt install nginx

RHEL/AlmaLinux/Rocky Linux:

sudo dnf update nginx
nginx -v

После обновления — обязательно проверить конфиг и перезагрузить. Иногда после мажорного обновления nginx меняет поведение директив и конфиг перестаёт валидироваться:

sudo nginx -t && sudo systemctl reload nginx

nginx -t проверяет синтаксис конфига. Если ошибок нет — reload применяет новую версию без даунтайма. Если есть — разбираешь что сломалось перед применением.

ЕСЛИ ОБНОВИТЬСЯ ПРЯМО СЕЙЧАС НЕВОЗМОЖНО

Иногда production нельзя трогать прямо сейчас: релиз, freeze, согласования. На этот случай — конфигурационная митигация.

Уязвимость требует двух условий одновременно: unnamed capture ($1, $2) и вопросительный знак в replacement. Убери одно — баг не сработает.

Способ первый — заменить unnamed captures на named. Named captures работают иначе на уровне кода и не задействуют уязвимый путь:

# Было — уязвимо (unnamed capture, знак вопроса):
rewrite ^/api/(.*)$ /internal?id=$1 last;

# Стало — безопасно (named capture):
rewrite ^/api/(?P.*)$ /internal?id=${id} last;

(?P.*) — это named capture с именем id. ${id} — обращение к нему по имени. Функционально то же самое, но другой путь в коде.

Способ второй — убрать rewrite с вопросительным знаком, переписать через proxy_pass:

# Вместо rewrite:
location ~ ^/api/(.+)$ {
    proxy_pass http://backend/internal?id=$1;
}

proxy_pass не проходит через ngx_http_rewrite_module — уязвимость не применима.

Это временная мера. Обновление всё равно нужно.

KUBERNETES И INGRESS NGINX — ОСОБЫЙ СЛУЧАЙ

Если используешь Ingress NGINX Controller в Kubernetes — ситуация сложнее.

В марте 2026 года Kubernetes-проект вывел Ingress NGINX из поддержки. Последняя версия — v1.15.1. Она содержит тот же ngx_http_script.c с той же уязвимостью. И upstream-патча не будет — проект закрыт.

Особенность ingress controller: он обычно доступен с публичного интернета прямо на edge кластера. NGINX Rift здесь — уязвимость без аутентификации, достижимая напрямую из интернета, без патча.

Миграция: nginx-gateway-fabric (официальный наследник от F5), Traefik, или Envoy. Это не быстрая задача, но она уже не опциональная.

ПОЧЕМУ ЭТО НЕ «ЕЩЁ ОДИН CVE»

nginx работает примерно на 34% всех веб-серверов мира. Он стоит перед backend, перед базами данных, перед API — первым получает каждый входящий запрос, до любой другой защиты. Cloudflare сверху? Правила WAF? Отлично. Но запросы от легитимных пользователей всё равно доходят до nginx — и один из них может быть crafted.

Разница между этим CVE и большинством других в том, что:
— баг в коде который выполняется при обработке каждого rewrite-запроса
— не требует аутентификации
— не требует особых прав
— работает через обычный HTTP
— PoC публичный с первого дня

Обновление nginx — это не «поставлю на выходных». Эксплуатация уже идёт.

Leave your thought here

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поддержать автора

Если вам понравилась статья — вы можете поддержать автора.

Crypto donation button by NOWPayments