18-летнее RCE в nginx (CVE-2026-42945)

13 мая была исправлена уязвимость в популярном для нагруженных систем веб-сервере nginx: CVE-2026–42945, потенциально могущая привести к RCE. Уязвимость появилась 18 лет (2008 год) назад в версии 0.6.27.
Для её эксплуатации в конфиге сервера должна быть определённая комбинация директив, не так что бы у всех присутствующая, но местами имеющая место, например такая:
rewrite ^(.*) /new?c=1;
set $myvar $1;
return 200 $myvar;
- сначала идёт директива rewrite, где (первый аргумент) регулярное выражение с выделяемым параметром (что-то в круглых скобках) заменяется на (второй аргумент) путь, содержащий в себе знак вопроса;
- директива set (вместо неё так же подойдёт второй rewrite или if), которая использует выделенный параметр из исходного перезаписанного пути (в данном случае это $1).
Уязвимость работает так:
- первая директива rewrite, натыкаясь на знак вопроса, устанавливает внутренний флаг is_args, означающий «сейчас собираем get-параметры для заменённого урла, надо всё экранировать», и (в этом и суть бага) забывает сбрасывать этот флаг в конце своей работы;
- последующая директива set, при формировании значения для $myvar, ошибочно применяет установленный ранее is_args, и записывает в my_var экранированное значение выделенного параметра $1; проблема в том, что буфер для $myvar выделяется раньше, ещё до выполнения подстановок, и его длина считается с is_args=0, то есть экранированное значение оказывается длиннее чем выделенный буфер, из-за чего запись происходит вне выделенного буфера в другие структуры данных сервера. Чтобы это произошло, достаточно прислать запрос с символами, подлежащими экранированию, например знаками «плюс», в месте выделения параметра регулярного выражения.
Если на хосте нет ALSR, то данная уязвимость может эксплуатироваться для удалённого выполнения кода с правами рабочего процесса nginx, есть PoC (там не эксплойт в чистом виде, демонстрация в песочнице).
Уязвимость исправлена в стабильной ветке nginx 1.30.1, и в новой девелоперской 1.31.0. ссылка на коммит.
Примечательно, что 14 лет назад (2012 год) похожая ошибка уже исправлялась в другом месте рядом.
-------
На сайте F5 имеется рекомендация по временной нейтрализации уязвимости на случай невозможности быстро обновить версию nginx — нужно заменить неименованные выделенные параметры на именованые, и в этом случае, по их словам, уязвимость проявляться не будет. Пример оттуда:
было: rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
стало: rewrite ^/users/(?[0-9]+)/profile/(?.*)$ /profile.php?id=$user_id&tab=$section last;
Информация об уязвимости была предоставлена Zhenpeng (Leo) Lin из DepthFirst. Кроме того, он же сообщил о следующих проблемах, которые тоже исправлены:
- CVE-2026–40701 (коммит) use-after-free при использовании ssl_verify_client+ssl_ocsp (вроде бы без RCE)
- CVE-2026–42934 (коммит) чтение за пределами буфера в utf-8 парсере при специфических обстоятельствах, может привести к небольшой утечке данных или крашу рабочего процесса
- CVE-2026–42946 (коммит) чрезмерное выделение памяти и чтение за пределами буфера при использовании модулей scgi/uwsgi, проблема проявляется при наличии злонамеренного бекэнда (upstream) через указанные протоколы, либо при mitm канала общения с бекэндом, может привести к чтению памяти nginx или крашу рабочего процесса
>>> Официальное объявление F5
