Repository di ricerca completo su CVE-2026-42945 con analisi dell'heap buffer overflow, exploit RCE (heap spray + Feng Shui), script di rilevamento e indicazioni per il patching della vulnerabilità del modulo rewrite di NGINX.
Overflow del buffer heap in NGINX ngx_http_rewrite_module
| Metrica | Valore |
|---|---|
| CVSS v4.0 | 9.2 (Critico) |
| CVSS v3.1 | 8.1 (Alto) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | 122 — Overflow del buffer basato su heap |
| Introdotta | Giugno 2008 — v0.6.27 |
| Scoperta | Aprile 2026 — DepthFirst Research |
| Corretta | 13 maggio 2026 — v1.30.1, v1.31.0 |
| Pubblicazione CVE | 21 maggio 2026 |
| Durata | ~18 anni (non rilevata) |
| Commit di correzione | 524977e7c534e87e5b55739fa74601c9f1102686 |
Un attaccante remoto non autenticato può innescare un overflow del buffer heap deterministico nei processi worker di NGINX inviando una richiesta HTTP appositamente predisposta a un server con una specifica configurazione di rewrite + set/if/rewrite. L'overflow corrompe i metadati dell'heap (puntatori ngx_pool_cleanup_t), consentendo Remote Code Execution (RCE) tramite tecniche di heap spray e Feng Shui.
server { listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
**Requisiti chiave:**
- Una direttiva `rewrite` la cui sostituzione contiene `?` (separatore di query-string)
- Una successiva direttiva `set`, `if` o `rewrite` che fa riferimento a una **cattura PCRE senza nome** (`$1`, `$2`, ecc.)
- Il `?` nella sostituzione della `rewrite` attiva `ngx_http_script_start_args_code` che imposta `e->is_args = 1`
### Cosa può ottenere un attaccante
| Capacità | Descrizione |
|-----------|-------------|
| **Denial of Service** | Crash deterministico dei processi worker, causando cicli di respawn (funziona indipendentemente dall'ASLR) |
| **Remote Code Execution** | Con ASLR disabilitato (o bypassato tramite sovrascrittura parziale), raggiungere RCE completa come utente nginx |
| **Esfiltrazione di dati** | Attraverso primitive di lettura della memoria, estrarre dati sensibili dall'heap dei worker |
| **Persistenza** | Installare backdoor tramite l'esecuzione di codice nella memoria dei processi worker |
---
## 2. Analisi della causa principale
### Il motore di script a due passaggi
Il modulo `ngx_http_rewrite_module` di NGINX utilizza un **motore di script a due passaggi** in `src/http/ngx_http_script.c`:
1. **Passaggio di lunghezza** (`ngx_http_script_run`): itera su tutti i codici di script per calcolare la dimensione totale del buffer necessaria. Scrive le lunghezze in `le.ip` e `le.pos`.
2. **Passaggio di copia** (`ngx_http_script_copy_len`/`_code`): itera nuovamente, scrivendo i byte effettivi nel buffer pre-allocato in `e->ip` e `e->pos`.
Ogni codice di script ha due handler: uno per ciascun passaggio. Per esempio:
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### Il flag `is_args`
Il flag `e->is_args` sulla **struttura del motore** (`ngx_http_script_engine_t`) controlla come il passaggio di copia gestisce determinati caratteri:```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, il codice di copia per i riferimenti di cattura $N chiama ngx_escape_uri() con NGX_ESCAPE_ARGS, che espande:
+ → %2B (1 byte → 3 byte, +200%)% → %25 (1 byte → 3 byte, +200%)& → %26 (1 byte → 3 byte, +200%)Il flusso di esecuzione per il pattern vulnerabile:``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. Durante la **valutazione della riscrittura**, il motore incontra `?` nella stringa di sostituzione, che attiva `ngx_http_script_start_args_code`, impostando `e->is_args = 1`.
2. La riscrittura modifica l'URI della richiesta e poi continua alla direttiva successiva.
3. **`e->is_args` NON VIENE MAI AZZERATO**.
Quindi:```
set $original_endpoint $1;
le) viene creato per il passaggio di lunghezza: ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
Questo azzera correttamente le.is_args = 0, quindi il passaggio di lunghezza restituisce la lunghezza di cattura grezza, non escapata.
e, che ha ancora e->is_args = 1 dal passaggio 1. Il passaggio di copia applica l'URI-escaping, espandendo ogni carattere escapabile da 1 byte a 3 byte all'interno di un buffer dimensionato per la lunghezza grezza — heap overflow.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
Il rapporto di espansione è `7 + (n_escapable * 2)` dove `n_escapable` è il conteggio di `+`, `%` e `&` nella cattura.
---
## 3. Meccaniche di sfruttamento
### Panoramica
| Step | Tecnica | Descrizione |
|------|---------|-------------|
| 1 | Overflow | Invia URI modificato con padding `+` per far overfloware il buffer heap |
| 2 | Heap Spray | POST di corpi grandi a `/spray` per riempire l'heap con dati controllati |
| 3 | Feng Shui | Disporre le allocazioni in modo che il bersaglio dell'overflow (`ngx_pool_cleanup_t`) sia adiacente |
| 4 | Corrompi handler | L'overflow sovrascrive `ngx_pool_cleanup_t.handler` con l'indirizzo di `system()` |
| 5 | Attiva cleanup | Attendi la distruzione del pool → `system(cmd)` esegue il comando dell'attaccante |
| 6 | Reverse shell | Collega a un payload di reverse shell per accesso interattivo |
### Feng Shui tra richieste
**Il Feng Shui a singola richiesta fallisce** perché l'overflow corrompe i metadati del pool (`->d.next`, `->d.failed`) prima di raggiungere il puntatore `cleanup`. Quando il pool viene distrutto alla fine della richiesta, i metadati corrotti causano un **crash prima che `system()` venga chiamato**.