
SolarWinds Serv-U CVE-2026-28318: unauthentifizierter Content-Encoding: deflate-Absturz. Ursachenanalyse (ungültiger Free eines internen Zeigers -> Heap-Korruption) + DoS-only PoC. Behoben in 15.5.4 Hotfix 1.
Root-Cause-Analyse + DoS Proof-of-Concept. Das öffentliche Advisory klassifiziert dies als einen nicht authentifizierten Denial-of-Service / unkontrollierten Ressourcenverbrauch. Die Binäranalyse zeigt, dass der zugrundeliegende Fehler Memory-Safety ist: ein ungültiger
free()-Aufruf eines Innenzeigers im HTTP-deflate-Dekodierungspfad, der den Prozess-Heap beschädigt (STATUS_HEAP_CORRUPTION,0xC0000374). Es handelt sich nicht um eine Dekompressionsbombe, und der Absturz ist unabhängig von der dekomprimierten Größe.
| Product | SolarWinds Serv-U (FTP / MFT / File Server) |
| Vulnerable | 15.5.4 und früher in diesem Zweig ohne Hotfix 1 (Analyse durchgeführt auf Build 15.5.4.108) |
| Fixed | Serv-U 15.5.4 Hotfix 1 (veröffentlicht am 2026-06-04) |
| Vector | Nicht authentifiziert, Netzwerk (HTTP/HTTPS-Verwaltungs-/Web-Port) |
| Public class | CWE-400 Unkontrollierter Ressourcenverbrauch · DoS · CVSS 7.5 · CISA KEV |
| Actual class | CWE-763 Freigabe eines ungültigen Zeigers / CWE-590 Freigabe von Speicher, der nicht auf dem Heap liegt → Heap-Korruption |
Betrifft nur den HTTP/HTTPS-Listener (den Web-/Verwaltungspfad). FTP/FTPS/SFTP liegen nicht auf diesem Codepfad.
Jede HTTP-Anfrage mit Content-Encoding: deflate mit einem gültigen Deflate-Body stürzt den Dienst ab. Der Handler dekomprimiert den Body, dann gibt er den Zeiger auf den komprimierten Body frei und tauscht den dekomprimierten Puffer ein – aber dieser Zeiger ist ein Innenzeiger in den HTTP-Empfangspuffer (er zeigt auf den Body, unmittelbar nach dem \r\n\r\n), keine Heap-Allokationsbasis. Das Aufrufen von free() auf einen nicht-basierten, unausgerichteten Zeiger beschädigt den Heap und der Prozess stirbt.
Da der Fehler darin liegt, wie der Body-Zeiger freigegeben wird – nicht darin, wie viele Daten erzeugt werden –, reicht bereits ein ~25 Byte großer komprimierter Body (der auf wenige KB dekomprimiert), um ihn zuverlässig zum Absturz zu bringen. Der Speicherverbrauch wächst nicht; es ist keine "Zip/Deflate-Bombe".
Die Deflate-Dekodierungsroutine befindet sich in RhinoNET.dll (Serv-U's Netzwerkbibliothek) und wird vom HTTP-Empfangspfad (ProcessReceive) erreicht, sobald der Header-Parser das "deflate"-Flag setzt, wenn er Content-Encoding: deflate sieht.
Vereinfacht wird die Routine als decode(this, &bodyPtr, &bodyLen) aufgerufen und tut:
1. inflate bodyPtr[0..bodyLen] -> grows an accumulator buffer `acc` (stock zlib, bounded, correct)
2. free(*bodyPtr) <-- *bodyPtr is an INTERIOR pointer into the receive buffer
3. *bodyPtr = acc // replace compressed body with decompressed buffer
4. *bodyLen = total
Schritt 2 ist der Fehler. *bodyPtr ist kein unabhängig allokierter Block: Er zeigt auf den Request-Body innerhalb des einzelnen HTTP-Empfangspuffers, d. h. receive_buffer + header_length. Das Freigeben eines Innenzeigers (und 16-Byte-fehlausgerichteten) Zeigers führt dazu, dass der Allokator einen angreifergesteuerten Bereich als Heap-Chunk-Header interpretiert → Heap-Metadaten-Korruption → 0xC0000374.
Beide der "offensichtlichen" Hypothesen sind falsch, zur Laufzeit verifiziert:
zlib1.dll!inflate und respektiert avail_out bei jedem Aufruf (beobachtet über 100+ Chunks; keine Out-of-Bounds-Schreibvorgänge).prev_total + produced + 1 allokiert und genau so viel geschrieben — eng, kein Überlauf.Die Korruption ist ausschließlich der ungültige free()-Aufruf in Schritt 2.
Zur Laufzeit (Frida) gegen Serv-U 15.5.4.108 erfasst, während eine Content-Encoding: deflate-Anfrage gesendet wurde, deren Body zu "A" * 8192 dekomprimiert:
…ce — mod 16 == 14. Heap-Allokationsbasen sind 16-Byte-ausgerichtet, also ist dies keine Allokationsbasis; es ist ein Innenzeiger.\r\n\r\n:
…tream\r\nContent-Length: 26\r\nConnection: close\r\n\r\n
ed c1 01 0d 00 …).ntdll.dll, Ausnahme 0xC0000374 (STATUS_HEAP_CORRUPTION), wobei der Aufruf vom free im Deflate-Handler von RhinoNET.dll stammt. Die letzte Heap-Operation vor dem Absturz ist genau dieses free(bodyPtr).free()-Aufruf in unseren Tests schnell fehl (0xC0000374), und wir haben keine Codeausführung erreicht. Behandeln Sie dies als Pre-Auth-Heap-Korruptions-DoS mit einer Memory-Safety-Ursache; gehen Sie nicht von RCE aus.Erfordert Python 3 (nur Standardbibliothek). Richten Sie es auf einen Serv-U-HTTP-Listener aus, den Sie testen dürfen. Unter Windows verwendet es einen Get-NetTCPConnection-Aufruf, um die Listener-PID zu lesen, und das Anwendungsereignisprotokoll, um den Heap-Korruptionsabsturz zu bestätigen.
python poc_verify.py # default 127.0.0.1:80, tiny packet, 1 shot
python poc_verify.py --host <ip> --port 80
python poc_verify.py --big # body decompresses to 8192 bytes
python poc_verify.py --shots 3
python poc_verify.py --no-events # skip event-log check (no privileges needed)
Der PoC erstellt eine minimale Anfrage:
POST / HTTP/1.1
Host: <target>
Content-Encoding: deflate
Content-Type: application/octet-stream
Content-Length: <n>
Connection: close
<raw-deflate body — even a few dozen bytes is enough>
Es meldet PASS, wenn der Dienst abgestürzt ist (Listener-PID geändert / 0xC0000374-Ereignis erschienen) und FAIL, wenn er überlebt hat (bereits gepatcht, nicht betroffen oder der Body wurde nicht als Deflate verarbeitet).
Content-Encoding-Header des HTTP/HTTPS-Listeners entfernen oder ablehnen, z. B. auf einem Reverse-Proxy:
if ($http_content_encoding) { return 400; }