
CVE-2026-111497 RCE-PoC für ein gepinntes offizielles Docker-Image für WordPress
Dieses reine Quellcode-PoC reproduziert unauthentifizierte Befehlsausführung gegen ein gepinntes Docker Official Image für WordPress.
Eine einzige pingback.ping-Anfrage veranlasst WordPress, während derselben PHP-Anfrage zweimal eine Angreifer-URL abzurufen. Die erste Antwort korrumpiert einen PHP-Handler über Brotli. Der Retry-Header startet Bash und gibt das Lab-Flag zurück.
Das Profil ist zielspezifisch. Es erhebt keinen Anspruch auf aktuelle WordPress-Images, andere Digests oder einen Speicherfehler in WordPress Core.
WARNUNG: Führe dieses PoC nur im enthaltenen Lab auf einem System aus, das dir gehört. Es enthält eine funktionierende RCE-Payload.
/flag.txt, und das Flag wird in der XML-RPC-Antwort zurückgegeben.sh zu bash zu sleep auf.| Element | Wert |
|---|---|
| Ziel | docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5 |
| Image-ID | c64dd89c00079939f18d70489e7c3e30cb071e8581824ab2de688f9f4d70d076 |
| Plattform | Linux amd64, Debian 13.7 |
| Anwendung | WordPress 7.1.3, Apache 2.4.69 prefork |
| Laufzeit | PHP 8.3.36 NTS |
| Decoder | libbrotli1:amd64 1.1.0-2+b7 |
Dieses Linux/amd64-Manifest wurde bei der Veröffentlichung von wordpress:latest ausgewählt. Das aktuelle latest-Tag wählt es nicht mehr aus.
Das Lab führt dieses unveränderte Docker Official Image mit rootless Podman aus. Es injiziert keine Brotli-Bibliothek.
CVE-2026-111497 liefert die Decoder-Korruption. WordPress liefert den unauthentifizierten Abrufpfad über pingback.ping.
Der fehlerhafte Stream kopiert sechs Bytes aus dem Live-Zeiger des system-Handlers in den strtolower-Handler. Beide Zeiger verwenden dieselbe ASLR-geladene libphp.so-Basis. Daher benötigt das Profil kein absolutes Adress-Leak.
Das Profil hängt weiterhin von der exakten Brotli-, PHP-, glibc-, cURL-, Requests-, Apache-, Allocator- und Anfragehistorie ab. Die erste Antwort verwendet einen 161-Byte-Header und einen 23.069.816-Byte-Body. Der Origin sendet 23.069.752 Bytes, wartet eine Sekunde und sendet die letzten 64 Bytes.
Der Decoder gibt nach der Korruption einen Fehler zurück. Requests wiederholt den Versuch ohne Content-Decoding nach CURLE_BAD_CONTENT_ENCODING. Sein erster Header-Name erreicht den modifizierten Handler und startet den festen Bash-Befehl.
Der Anwendungspfad erfordert diese Bedingungen:
/xmlrpc.php ist erreichbar, und pingback.ping ist aktiviert.Das Lab erzeugt diese Bedingungen ohne Plugin oder Instrumentierung auf der Opferseite.
generate_payloads.py ist die maßgebliche Payload-Quelle. Das Repository verfolgt keine vorgefertigten Payload-Binärdateien.
Der Generator verwendet nur die Python-Standardbibliothek. Er arbeitet offline und sendet keinen Traffic und führt keine Befehle aus. Er definiert die Profilkonstanten und Serialisierungsstufen aus RFC 7932.
verify.sh generiert alle Fragmente neu. Es verifiziert ihre Größen, Hashes, Zwischen-Bit-Offsets und die Ein-Bit-Selektor-Beziehung.
Der getestete Host verwendete Ubuntu 24.04.4 unter WSL2 auf amd64. Er verwendete rootless Podman 4.9.3, Bash 5.2.21 und Python 3.12.3.
Die Mindestanforderungen sind Linux amd64, rootless Podman, Bash, Python 3.8 oder später, ASLR-Modus 2 und Standard-GNU-Benutzerwerkzeuge. Halte Port 18170 und das Subnetz 93.184.218.0/24 frei oder wähle Alternativen. Ein SELinux-Host im Enforcing-Modus kann die Bind-Mounts ablehnen.
Bevor du das Lab ausführst, ziehe die unveränderlichen Images:
podman pull docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5
podman pull docker.io/library/wordpress@sha256:65d5f185a6f539803a177ea9cdd5ad632ae24427bea114447e67a6fcd5d8bfe8
podman pull docker.io/library/mariadb@sha256:33a6653ab666774f48818120045f9367a81cd4c54c027412fe294a7d1274e2dc
Machen Sie die Skripte ausführbar und überprüfen Sie dann das Quellpaket:
chmod +x generate_payloads.py verify.sh run.sh
./verify.sh
Führe jeden Modus mit einem neuen Tag aus:
| Modus | Befehl | Erforderliches Ergebnis |
|---|---|---|
| Positiv | ./run.sh standard | Gibt das Flag zurück und druckt PoC positive: |
| Beobachtbar | ./run.sh observable | Zeichnet außerdem sichtbare bash- und sleep-Prozesse auf |
| Selektor | ./run.sh selector | Wiederholt den Versuch, hält das Flag jedoch aus der Antwort heraus |
Der Selektor ändert ein Bit an Byte-Offset 1066. Es handelt sich um eine kausale Kontrolle innerhalb desselben Images, nicht um eine Kontrolle mit festem Decoder.
Die optionalen Argumente sind der Modus, der Tag, der Host-Port und das dritte Netzwerk-Oktett:
./run.sh standard trial2 18171 219
Der Runner schreibt Nachweise nach runs/<tag>/. Die wichtigsten Dateien sind:
VERDICT.txt: Ergebnis und Anzahl der Anfragenclient-request.raw und client-response.raw: eingehende Wire-Datenorigin-evidence/origin-events.json: beide ausgehenden Anfragen und Retry-Headeroracle-match.txt: der Flag-Treffer in der Antwortpayloads/identity.json: Metadaten des generierten ProfilsMANIFEST.sha256: Hashes für alle NachweisdateienDer Runner verwendet ein internes Podman-Netzwerk und veröffentlicht WordPress nur auf 127.0.0.1. Der Client akzeptiert keine Zieladresse. Der Origin akzeptiert keine Befehlseingaben. Der feste Befehl liest nur das synthetische Flag.
Der Runner entfernt den Flag-Wert aus der Apache-Umgebung, bevor Apache startet. Er erstellt außerdem frische Anmeldedaten und entfernt nur Ressourcen des aktuellen Laufs.
Die Aufteilung der Antwort und die Prozesshistorie sind Exploit-Eingaben. Wenn ein Lauf fehlschlägt, wiederhole das unveränderte Profil mit einem neuen Tag. Passe nach einem fehlgeschlagenen Lauf keine Adressen oder Payload-Bytes an.
Dieses Paket belegt keine Portabilität über Image-Digests, PHP-Builds, Architekturen, Allokatoren oder Antwortzeitpläne hinweg. Ein anderes Ziel kann die Ausführung stoppen oder lediglich einen Absturz verursachen.
Upstream hat die gepflegten Brotli-Branches in 1.0.10, 1.1.1 und 1.2.1 korrigiert. Distributionsanbieter können den Fix per Backport übernehmen. Verwende die Herstellerempfehlung und das Paket-Changelog, nicht nur die angezeigte Version.