
PoC de RCE para CVE-2026-111497 en una imagen oficial de Docker de WordPress fijada
Esta PoC de solo código fuente reproduce la ejecución de comandos sin autenticación contra una imagen oficial de Docker fijada para WordPress.
Una única solicitud pingback.ping hace que WordPress obtenga una URL del atacante dos veces durante la misma solicitud PHP. La primera respuesta corrompe un manejador de PHP mediante Brotli. La cabecera de reintento inicia Bash y devuelve la flag del laboratorio.
El perfil es específico del objetivo. No afirma nada sobre las imágenes actuales de WordPress, otros digests ni un error de memoria en WordPress Core.
ADVERTENCIA: Ejecute esta PoC solo en el laboratorio incluido, en un sistema que sea de su propiedad. Contiene una carga útil RCE funcional.
/flag.txt nuevo y la flag se devuelve en la respuesta XML-RPC.sh a bash a sleep.| Elemento | Valor |
|---|---|
| Objetivo | docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5 |
| ID de imagen | c64dd89c00079939f18d70489e7c3e30cb071e8581824ab2de688f9f4d70d076 |
| Plataforma | Linux amd64, Debian 13.7 |
| Aplicación | WordPress 7.1.3, Apache 2.4.69 prefork |
| Entorno de ejecución | PHP 8.3.36 NTS |
| Decodificador | libbrotli1:amd64 1.1.0-2+b7 |
Este manifiesto Linux/amd64 fue seleccionado por wordpress:latest en el momento de su publicación. La etiqueta latest actual ya no lo selecciona.
El laboratorio ejecuta esta imagen oficial de Docker sin modificaciones con Podman sin root. No inyecta ninguna biblioteca Brotli.
CVE-2026-111497 proporciona la corrupción del decodificador. WordPress proporciona la ruta de obtención sin autenticación a través de pingback.ping.
El flujo malformado copia seis bytes desde el puntero del manejador system activo al manejador strtolower. Ambos punteros usan la misma base de libphp.so cargada por ASLR. Por lo tanto, el perfil no necesita una fuga de dirección absoluta.
El perfil sigue dependiendo del Brotli, PHP, glibc, cURL, Requests, Apache, asignador e historial de solicitudes exactos. La primera respuesta usa una cabecera de 161 bytes y un cuerpo de 23.069.816 bytes. El origen envía 23.069.752 bytes, espera un segundo y envía los 64 bytes finales.
El decodificador devuelve un error después de la corrupción. Requests reintenta sin decodificación de contenido tras CURLE_BAD_CONTENT_ENCODING. El nombre de su primera cabecera alcanza el manejador modificado e inicia el comando Bash fijo.
La ruta de la aplicación requiere estas condiciones:
/xmlrpc.php es accesible y pingback.ping está habilitado.El laboratorio crea estas condiciones sin un plugin ni instrumentación del lado de la víctima.
generate_payloads.py es la fuente autoritativa de las cargas útiles. El repositorio no rastrea binarios de carga útil precompilados.
El generador usa solo la biblioteca estándar de Python. Funciona sin conexión y no envía tráfico ni ejecuta comandos. Define las constantes del perfil y las etapas de serialización a partir de RFC 7932.
verify.sh regenera todos los fragmentos. Verifica sus tamaños, hashes, desplazamientos de bits intermedios y la relación del selector de un bit.
El host probado usó Ubuntu 24.04.4 bajo WSL2 en amd64. Usó Podman sin root 4.9.3, Bash 5.2.21 y Python 3.12.3.
Los requisitos mínimos son Linux amd64, Podman sin root, Bash, Python 3.8 o posterior, modo ASLR 2 y las herramientas de usuario estándar de GNU. Mantenga libre el puerto 18170 y la subred 93.184.218.0/24, o seleccione alternativas. Un host con SELinux en modo enforcing puede rechazar los montajes bind.
Antes de ejecutar el laboratorio, descargue las imágenes inmutables:
podman pull docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5
podman pull docker.io/library/wordpress@sha256:65d5f185a6f539803a177ea9cdd5ad632ae24427bea114447e67a6fcd5d8bfe8
podman pull docker.io/library/mariadb@sha256:33a6653ab666774f48818120045f9367a81cd4c54c027412fe294a7d1274e2dc
Haz que los scripts sean ejecutables, luego verifica el paquete de origen:
chmod +x generate_payloads.py verify.sh run.sh
./verify.sh
Ejecute cada modo con una nueva etiqueta:
| Modo | Comando | Resultado requerido |
|---|---|---|
| Positivo | ./run.sh standard | Devuelve la flag e imprime PoC positive: |
| Observable | ./run.sh observable | También registra los procesos visibles bash y sleep |
| Selector | ./run.sh selector | Reintenta pero mantiene la flag fuera de la respuesta |
El selector cambia un bit en el desplazamiento de byte 1066. Es un control causal de la misma imagen, no un control de decodificador fijo.
Los argumentos opcionales son el modo, la etiqueta, el puerto del host y el tercer octeto de red:
./run.sh standard trial2 18171 219
El runner escribe la evidencia en runs/<tag>/. Los archivos principales son:
VERDICT.txt: resultado y recuentos de solicitudesclient-request.raw y client-response.raw: datos de la red entranteorigin-evidence/origin-events.json: ambas solicitudes salientes y las cabeceras de reintentooracle-match.txt: la coincidencia de la flag en la respuestapayloads/identity.json: metadatos del perfil generadoMANIFEST.sha256: hashes de todos los archivos de evidenciaEl runner utiliza una red interna de Podman y publica WordPress solo en 127.0.0.1. El cliente no acepta ninguna dirección de destino. El origen no acepta entrada de comandos. El comando fijo lee únicamente la flag sintética.
El runner elimina el valor de la flag del entorno de Apache antes de que Apache se inicie. También crea credenciales nuevas y elimina únicamente los recursos de la ejecución actual.
La división de la respuesta y el historial de procesos son entradas del exploit. Si una ejecución falla, repita el perfil sin cambios con una nueva etiqueta. No ajuste las direcciones ni los bytes del payload después de una ejecución fallida.
Este paquete no establece portabilidad entre digests de imágenes, compilaciones de PHP, arquitecturas, asignadores de memoria ni programaciones de respuesta. Un objetivo diferente puede detener la ejecución o provocar únicamente un fallo.
El proyecto upstream corrigió las ramas mantenidas de Brotli en 1.0.10, 1.1.1 y 1.2.1. Los proveedores de distribuciones pueden aplicar el parche retroactivamente. Utilice el aviso del proveedor y el changelog del paquete, no solo la versión mostrada.