
Laboratorio Docker local para reproducir CVE-2026-3844, una carga arbitraria de archivos no autenticada que lleva a RCE en el plugin Breeze Cache de WordPress. Compara la versión vulnerable 2.4.4 con la parcheada 2.4.5 usando servicios aislados y un PoC de mínimo daño.
Laboratorio Docker local para reproducir y comparar el comportamiento de CVE-2026-3844 en el plugin Breeze Cache de WordPress.
Este repositorio demuestra el comportamiento vulnerable en Breeze Cache 2.4.4 y lo compara con el comportamiento corregido en Breeze Cache 2.4.5. El laboratorio utiliza dos servicios WordPress aislados, uno vulnerable y otro parcheado, además de un servidor de carga útil local dentro de la red Docker.
La prueba de concepto es intencionalmente de mínimo daño: no utiliza una webshell, no expone un parámetro de comando, no inicia una reverse shell y no requiere leer archivos del interior del contenedor. La prueba se basa en el comportamiento HTTP observable desde el host.
CVE-2026-3844 afecta al plugin Breeze Cache para WordPress hasta la versión 2.4.4 inclusive. La ruta de código vulnerable está relacionada con la funcionalidad de almacenamiento en caché local de Gravatar del plugin, específicamente el flujo fetch_gravatar_from_remote().
Cuando la opción de Breeze Almacenar archivos localmente - Gravatars está habilitada, las versiones vulnerables pueden obtener un archivo remoto controlado por un atacante y almacenarlo en un directorio de caché público accesible web. Si el archivo obtenido es PHP, el servidor web puede ejecutarlo cuando se solicita a través de HTTP.
Este laboratorio reproduce ese comportamiento localmente:
vuln: WordPress + Breeze Cache 2.4.4patched: WordPress + Breeze Cache 2.4.5payload: servidor de carga útil local solo para Dockersrcset controladaEl resultado esperado es:
http://127.0.0.1:8081 / Breeze 2.4.4 → prueba de que el PHP se almacena en caché y se ejecutahttp://127.0.0.1:8082 / Breeze 2.4.5 → prueba de que el PHP no se almacena en caché, ni es legible ni ejecutable.
├── 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
Máquina host
│
├── 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 -> servidor de carga útil local
Red Docker
│
├── vuln -> WordPress objetivo vulnerable
├── patched -> WordPress objetivo parcheado
├── vuln_db -> MariaDB para WordPress vulnerable
├── patched_db -> MariaDB para WordPress parcheado
└── payload -> servidor HTTP estático Python
Los contenedores WordPress obtienen la carga útil a través de la URL de la red Docker:
http://payload:9100/<archivo-carga>.php
El host verifica el resultado mediante solicitudes HTTP normales a los servicios WordPress.
2.4.42.4.5fetch_gravatar_from_remote()inc/class-breeze-cache-cronjobs.phpbreeze-store-gravatars-locally debe estar habilitadaEl comportamiento vulnerable solo es alcanzable cuando la caché local de Gravatar está habilitada. Esta opción está deshabilitada por defecto en instalaciones típicas, pero este laboratorio la habilita intencionalmente para reproducir la ruta de código vulnerable.
En Breeze Cache 2.4.4, el flujo de localización de Gravatar puede extraer una URL remota del HTML relacionado con el avatar y pasar esa URL a fetch_gravatar_from_remote().
La versión vulnerable carece de suficiente validación en torno al archivo remoto:
.phpEl archivo resultante se almacena en:
/wp-content/cache/breeze-extra/gravatars/
Cuando un archivo PHP se guarda allí y luego se solicita a través de Apache/PHP, el servidor lo ejecuta.
En Breeze Cache 2.4.5, el flujo parcheado agrega validación que evita que esta carga útil de laboratorio se almacene en caché como PHP ejecutable. En la reproducción local, el mismo disparador funciona contra 2.4.4 pero no expone el marcador de prueba contra 2.4.5.
Este laboratorio mantiene intencionalmente el servidor de carga útil local en lugar de usar un host de carga útil público.
download_url() de WordPress y la API HTTP de WordPress rechazan por defecto algunos nombres de host Docker privados y puertos no estándar. Los scripts de explotación públicos a menudo usan URLs de carga útil HTTPS públicas, que evitan esa restricción. Este laboratorio no hace eso.
Para mantener la reproducción completamente local, el script de semilla instala un pequeño helper de MU Plugin solo local que:
payload y payload.local80 y 9100Este helper no modifica el código fuente de Breeze. Tanto los servicios vulnerables como los parcheados usan versiones reales del plugin Breeze instaladas a través de WP-CLI.
El helper existe únicamente para hacer que el laboratorio Docker sea determinista y solo local.
Este repositorio está destinado únicamente a la investigación de seguridad local y la demostración de portafolio.
Medidas de seguridad:
localhost y servicios de red Dockercmd=La carga útil de la PoC imprime información benigna del entorno de ejecución de PHP:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<id del proceso>
host=<nombre de host del contenedor>
Esto demuestra el contexto de ejecución del código sin generar comandos de shell.
requestsInstalar la dependencia de Python:
python3 -m venv .venv
source .venv/bin/activate
pip install -r poc/requirements.txt
requirements.txt debe contener:
requests
Construir e iniciar el laboratorio:
docker compose down -v --remove-orphans
docker compose up -d --build
Verificar el estado de los servicios:
docker compose ps
Servicios esperados:
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
Verificar los registros de semilla:
docker compose logs --tail=120 vuln
docker compose logs --tail=120 patched
Líneas de registro esperadas:
[seed] WordPress ready at http://localhost:8081 with Breeze 2.4.4
[seed] WordPress ready at http://localhost:8082 with Breeze 2.4.5