
CVE-2026-42533: Pre-Auth-Heap-Overflow in nginx und Informationsleck durch PCRE-Capture-Clobbering in der Map/Script-Engine, verkettet zu RCE.
Pre-Auth-Heap-Pufferüberlauf und Heap-Information-Leak in nginx, verursacht durch fehlendes Speichern/Wiederherstellen des PCRE-Capture-Zustands über die beiden Durchläufe der Script-Engine. Eine zwischen zwei Capture-Referenzen ausgewertete Regex-map-Variable überschreibt r->captures, sodass der LEN-Durchlauf und der VALUE-Durchlauf unterschiedlicher Meinung darüber sind, wie groß ein Capture ist. Der Puffer wird für ein Capture dimensioniert und mit einem anderen gefüllt. Ein größeres Überschreiben ergibt einen Heap-Overflow mit vom Angreifer kontrolliertem Inhalt und Länge. Ein kleineres Überschreiben ergibt einen überdimensionierten Puffer, dessen nicht initialisiertes Ende an den Client zurückgegeben wird und libc- und Heap-Zeiger leakt.
Die beiden Primitiven lassen sich zu zuverlässiger Pre-Auth-Remote-Codeausführung verketten. Der Leak überwindet ASLR in einem einzigen GET, sodass für den Overflow ASLR nicht deaktiviert sein muss.
Writeup: https://cyberstan.co.uk/nginx-rce/ Advisory: F5 K000162097 Reporter: Stan Shaw (cyberstan)
nginx 0.9.6 bis 1.30.3 (stable) und 1.31.2 (mainline), erreichbar, seit die map-Direktive 2011 Regex-Unterstützung erhielt. Betroffen sind sowohl die http- als auch die stream-Module. Etwa 50 Direktiven an 13 Aufrufstellen, plus ein zweiter Pfad über benannte Captures (r->variables[]). Behoben in 1.30.4 und 1.31.3.
CVE-2026-42533-PoC/
├── exploits/ exploit and validator scripts
│ ├── poc.py numbered-capture proxy_method chain (crash/leak/rce/rce-det)
│ ├── calibrate.py find PL_OFF / HEAP_PAGE_OFF for --rce-det on your build
│ ├── leak_multi.py info leak on the return and set sinks
│ ├── test_all_sites.py ASan validator, all 13 overflow sites
│ └── named_capture_poc.py named-capture r->variables[] variant
├── configs/ nginx configs the exploits run against
│ ├── nginx_poc.conf crash / leak / rce
│ └── nginx_det.conf deterministic rce-det
├── docs/
│ └── EXPLOITATION.md full exploitation writeup
└── README.md
Führen Sie jeden unten stehenden Befehl vom Repository-Root aus, damit exploits/, configs/ und der Build-Baum ../nginx-1.30.1 alle aufgelöst werden.
exploits/poc.py ist der Hauptexploit (nummeriertes Capture, proxy_method-Senke). Seine Modi:
| Modus | Zweck |
|---|---|
poc.py --crash | Löst den Heap-Overflow aus; bei einem ASan-Build werden Schreibgröße und Stack bei ngx_http_script_copy_capture_code ausgegeben. |
poc.py --leak | Info-Leak: Gibt die libc- und Heap-Zeiger aus dem überdimensionierten Antwortbody aus. |
poc.py --rce | Vollständige Pre-Auth-RCE. Allgemeiner Einzelschuss (configs/nginx_poc.conf), ~66 % pro Versuch, bei Fehlschlag erneut ausführen. |
poc.py --rce-det | Vollständige Pre-Auth-RCE, deterministisch gegen die kontrollierte configs/nginx_det.conf. |
Eigenständige Skripte, die den Rest der Angriffsfläche des Bugs abdecken:
| Skript | Zweck |
|---|---|
exploits/leak_multi.py | Info-Leak über zwei weitere Evaluatoren (return, set), jeder libc+Heap-Zeiger gegen /proc/<pid>/maps bestätigt. Standardkonfiguration. |
exploits/test_all_sites.py | AddressSanitizer-Validator, der alle 13 Overflow-Aufrufstellen (http + stream) auslöst. |
exploits/named_capture_poc.py | Die Named-Capture-Variante (?P<name>...) über r->variables[] / copy_var_code, eine zweite Grundursache. |
Die Konfigurationen liegen in configs/: nginx_poc.conf (crash/leak/rce), nginx_det.conf (rce-det). Der vollständige Writeup ist docs/EXPLOITATION.md.
Linux, gcc, python3 und der nginx-1.30.1-Quellcode. Entwickelt und getestet auf Ubuntu 24.04.4, glibc 2.39, PCRE2 10.42, Python 3.12, vollständigem ASLR.
Zwei Builds. Ein sauberer Build für den Leak und die RCE, damit die Heap-Rückstände real sind. Ein AddressSanitizer-Build für den Crash und die Site-Validatoren, damit der Overflow mit exakter Schreibgröße und Stack gemeldet wird.
tar xf nginx-1.30.1.tar.gz
cd nginx-1.30.1
# clean build -> objs.dbg/nginx (leak, rce)
./configure --with-pcre --with-http_ssl_module --with-debug --builddir=objs.dbg
make -j"$(nproc)"
# ASan build with all the modules the site validator needs -> objs/nginx
./configure --with-pcre --with-http_ssl_module --with-http_v2_module \
--with-stream --with-stream_ssl_preread_module --with-stream_ssl_module \
--with-debug \
--with-cc-opt='-g -O0 -fsanitize=address -fno-omit-frame-pointer' \
--with-ld-opt=-fsanitize=address --builddir=objs
make -j"$(nproc)"
exploits/poc.py spricht mit einem laufenden nginx auf 127.0.0.1:8950. Starten Sie es in einem Terminal mit configs/nginx_poc.conf und führen Sie dann den gewünschten Modus in einem anderen aus. Die anderen drei Skripte starten und stoppen ihr eigenes nginx und benötigen daher nur NGINX_BIN.
mkdir -p run/logs
../nginx-1.30.1/objs/nginx -p run -c "$PWD/configs/nginx_poc.conf" # ASan build, foreground
python3 exploits/poc.py --crash
Erwartet: ein heap-buffer-overflow, WRITE of size 200 in ngx_http_script_copy_capture_code bei ngx_http_script.c:1404, aufgerufen aus ngx_http_complex_value in ngx_http_proxy_create_request.
../nginx-1.30.1/objs.dbg/nginx -p run -c "$PWD/configs/nginx_poc.conf" # clean build
python3 exploits/poc.py --leak
Erwartet: ein 8161-Byte-Body mit 2 geschriebenen Bytes und dem Rest als Heap-Rückstand. Ein libc-Zeiger bei Offset 0x08 und ein Heap-Zeiger bei 0x10.
../nginx-1.30.1/objs.dbg/nginx -p run -c "$PWD/configs/nginx_poc.conf" # clean build
python3 exploits/poc.py --rce # writes /tmp/PWNED via system()
Erwartet: ein Leak, etwa 40 Spray-Verbindungen, ein Overflow-Trigger, dann /tmp/PWNED mit der Ausgabe von id. Dies ist ein Einzelschuss und trifft im Dev-Build etwa zwei Drittel der Fälle; bei einem Fehlschlag stürzt der Worker ab und Sie führen es erneut aus. Siehe Abschnitt „Reliability" in docs/EXPLOITATION.md.
Gegen eine kontrollierte Konfiguration ist derselbe Bug ein deterministischer Einzelschuss. Er ermittelt die absolute Heap-Basis aus dem Leak in einer Zeile (heap_base = (leaked_ptr & ~0xfff) - 0x22000), platziert ein einziges gefälschtes Pool-Cleanup in einer gehaltenen Verbindung an einer bekannten Adresse und richtet das Cleanup des Opfer-Pools darauf statt auf den transienten Trigger-Body, den nginx vor dem Teardown freigibt.
mkdir -p run/logs
../nginx-1.30.1/objs.dbg/nginx -p run -c "$PWD/configs/nginx_det.conf" # controlled config
python3 exploits/poc.py --rce-det
nginx_det.conf ist eine Labor-Konfiguration (einzelner Worker, feste Puffer), deren Heap-Layout reproduzierbar ist, was die Offsets in poc.py (PL_OFF, HEAP_PAGE_OFF) gültig macht. PL_OFF ist der Offset von der Heap-Basis, an dem der gehaltene POST /b/-Cleanup-Body landet; er hängt von der exakten Allokationssequenz ab und verschiebt sich daher zwischen Builds, glibc-Versionen und Konfigurationen. Wenn --rce-det Recalibrate meldet, lesen Sie die korrekten Werte mit calibrate.py von einem laufenden Worker ab:
NGINX_BIN=../nginx-1.30.1/objs.dbg/nginx python3 exploits/calibrate.py
# prints e.g. set PL_OFF = 0x14426 , then edit it in exploits/poc.py
Der einzige andere Nicht-Erfolg ist eine ASLR-Ziehung, die ein 0x0a in die Cleanup-Adresse oder den Overflow-Body legt, was die Map-Regex nicht transportieren kann; das Tool meldet es und Sie führen es erneut aus. Ein Standard-Deployment ist nicht so vorhersagbar, verwenden Sie dort also --rce. Siehe „A deterministic build" in docs/EXPLOITATION.md.