
PoC цепочки RCE в nginx, не зависящей от ASLR, объединяющий утечку через переполнение чтения кучи PoolSlip (CVE-2026-9256) с переполнением rift (CVE-2026-42945) для достижения system() на стандартном nginx.
Первая публичная цепочка из двух недавно раскрытых багов движка rewrite в nginx, объединённых в единый
ASLR-независимый удалённый system() на штатном официальном образе nginx:1.30.0 Docker
(Debian 13, glibc 2.41) — без захардкоженных адресов, без перезапуска nginx, ~90 % на свежий worker.
$args → утечка живых libc + heap.is_args (только URL-безопасные байты) → 2-байтная частичная
перезапись указателя очистки limit_conn → ngx_destroy_pool проходит по нему → system(cmd).Оба — это одно и то же двухпроходное несоответствие is_args, направленное на два стока. Полный технический разбор: Writeup
Раскрытие и безопасность
- Обе CVE уже пропатчены и активно эксплуатируются в дикой природе. Обновитесь до nginx 1.30.2 (stable) или 1.31.1 (mainline) — учтите, что
1.30.1исправляет rift, но всё ещё уязвим к PoolSlip, поэтому только1.30.2закрывает оба. NGINX Plus: R36 P5 / R32 P7 / R37.0.1.1.- Это опубликовано только для обучения и авторизованного тестирования. Оно работает против встроенной локальной лаборатории Docker — не направляйте его на инфраструктуру, которой вы не владеете или на которую у вас нет письменного разрешения на тестирование.
| CVE | псевдоним | уязвимые | исправлено (nginx OSS) |
|---|---|---|---|
| CVE-2026-42945 | rift | 0.6.27 – 1.30.0 | 1.30.1 / 1.31.0 |
| CVE-2026-9256 | PoolSlip | 0.1.17 – 1.30.1 + 1.31.0 | 1.30.2 / 1.31.1 |
| Файл | Назначение |
|---|---|
nginx.conf | Правдоподобный конфиг API-шлюза (цель — limit_conn, rewrite миграции v1→v2, прокси загрузки, деградированная страница поиска). Без настройки аллокатора. |
run.sh | Поднимает локальную лабораторию: штатный nginx:1.30.0, обслуживающий nginx.conf, плюс медленный upstream, на хосте :19322. |
exp_official.py | Полная цепочка: утечка PoolSlip → вывод libc/heap → spray → groom → частичная перезапись rift → system(). |
exp_official.py), curl, Linux x86-64.run.sh использует perl (уже есть в штатном образе nginx) для медленного upstream, так что нет дополнительных пакетов, нет файла slow_backend и не нужен интернет. Сам бинарник nginx остаётся штатным.WRITEUP.md, зайдите через docker exec и выполните apt-get install gdb file binutils, затем загрузите gef.git clone https://github.com/y198nt/Nginx-chain-Rift-Poolslip
cd Nginx-chain-Rift-Poolslip
bash run.sh # stock nginx:1.30.0 on http://127.0.0.1:19322
python3 exp_official.py --cmd 'id > /tmp/rce_proof' # leak → overwrite → system()
docker exec nginx-rift-official cat /tmp/rce_proof # → uid=101(nginx) ...
exp_official.py — одноразовый (~90 % на свежий worker): он утекает один раз и стреляет один раз. Если
файл-доказательство пуст, groom промахнулся на слот — просто запустите заново.
docker rm -f nginx-rift-official # tear the lab down
rewrite ^/search/((.*))$ /lookup?$1$2 заставляет проход копирования установить
r->args.len за буфером; деградированная страница /search отражает $args в соседний heap.
После короткого прогрева указатель libpcre-cluster (фиксированный 0xb0ad08 ниже libc) и указатель
heap оседают на стабильных смещениях → libc_base и heap_base, ничего захардкоженного.limit_conn — ASLR-случайные старшие байты остаются нетронутыми →
ASLR-независимо.ngx_pool_cleanup_t{handler=&system, data=cmd, next=0}; закрытие жертвы запускает обход очистки в ngx_destroy_pool →
system(cmd).Смотрите Writeup для полного вывода, сессий gdb и тупиков/поворотов.
rewrite, чья замена содержит ? и ссылается на PCRE-захват
($1/$2), или на шаблон вложенного захвата вроде ^/x/((.*))$ → /y?$1$2. Проверьте конфиги на
такие случаи и переработайте проблемный rewrite/set до патча.$args (или любая переменная, производная от запроса, возвращаемая обратно) — это то, что превращает перечитывание
в утечку информации — не отражайте аргументы запроса дословно.%2B/+ в пути URI (GET /search/+++…), 503 от деградированной
страницы, отражающей длинный $args, и штормы SIGSEGV/перезапусков worker.