Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
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.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2023-6553 — Exploit de prueba de concepto e informe técnico para CVE-2023-6553, una vulnerabilidad de inclusión de archivos PHP no autenticada que permite la ejecución remota de código en el plugin Backup Migration de WordPress <=1.3.7. | Kitploit
Herramientas/GitHubGitHub/dungsocool/cve-2023-6553
Análisis de VulnerabilidadesAnálisis de CódigoExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y Educación
GitHubdungsocool/cve-2023-6553

CVE-2023-6553

Exploit de prueba de concepto e informe técnico para CVE-2023-6553, una vulnerabilidad de inclusión de archivos PHP no autenticada que permite la ejecución remota de código en el plugin Backup Migration de WordPress <=1.3.7.

Ver Repositorio
8hace 1 mesAú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-2023-6553

Inclusión de archivos en PHP que conduce a RCE — Plugin Backup Migration

Plugin: Backup Migration (backup-backup) ≤ 1.3.7

CVSS: 9.8 (Crítico)

CWE: CWE-98 — Control inadecuado del nombre de archivo para la declaración Include/Require

Requisito de autenticación: Ninguno

Impacto: Ejecución remota de código


1. ¿Qué es esta vulnerabilidad?

Backup Migration es un plugin de WordPress bastante popular (~90.000+ instalaciones activas) que ayuda a los usuarios a crear copias de seguridad. Durante el proceso de copia de seguridad, el plugin tiene un archivo llamado backup-heart.php ejecutándose en segundo plano: recibe información de configuración mediante cabeceras HTTP para saber qué directorio debe respaldarse, dónde se encuentra el archivo de configuración, etc.

El problema radica en que este archivo confía plenamente en las cabeceras HTTP enviadas por el cliente, toma el valor de la cabecera directamente hacia la ruta del archivo y luego usa require_once() para cargar el archivo desde esa ruta. Un atacante solo necesita enviar la cabecera Content-Dir apuntando a un directorio que contenga código PHP malicioso → el servidor automáticamente lo incluye y ejecuta.

Cabe destacar que el archivo backup-heart.php no requiere autenticación — solo comprueba si el método de solicitud es POST, sin verificar ningún nonce ni privilegios de usuario. Cualquier persona en internet puede enviarle una solicitud.

⇒ Esta es una vulnerabilidad zero-click.

AtributoValor
ID CVECVE-2023-6553
Puntuación CVSS9.8 (Crítico)
Pluginbackup-backup (Backup Migration) ≤ 1.3.7
AutenticaciónNo requerida
Interacción del usuarioNinguna (zero-click)
CorregidoVersión 1.3.8

2. Conocimientos previos

Inclusión de archivos en PHP

PHP tiene funciones como include(), require(), require_once() que se usan para incluir otros archivos PHP en el programa en ejecución. Cuando la ruta de archivo pasada a estas funciones proviene de la entrada del usuario sin validación, un atacante puede forzar al servidor a incluir cualquier archivo que desee:

  • LFI (Inclusión Local de Archivos): carga un archivo existente en el servidor — por ejemplo, un archivo de registro que ha sido "envenenado" con código PHP.
  • RFI (Inclusión Remota de Archivos): carga un archivo desde un servidor externo — requiere allow_url_include=On (normalmente deshabilitado por defecto).

Este CVE se clasifica como LFI — el atacante controla la ruta pasada a require_once() apuntando a un archivo PHP que el atacante ha logrado escribir en el servidor.

¿Por qué son peligrosas las cabeceras HTTP?

Muchos desarrolladores piensan que las cabeceras HTTP son metadatos "internos" conocidos solo por el servidor y el cliente. En realidad, los atacantes controlan el 100% del contenido de las cabeceras — pueden establecer cualquier nombre y valor de cabecera. Confiar en las cabeceras es igual que confiar en la entrada de un formulario: debe validarse.

define() y las constantes de PHP

define('NAME', $value) crea una constante utilizada en toda la aplicación. Una vez defineda, el valor no se puede cambiar. Si $value proviene de un atacante, todos los lugares que usan esa constante se ven afectados.

3. Análisis del código fuente — ¿Dónde se origina la vulnerabilidad?

Paso 1: Encontrar el Sink

Empecé usando grep para buscar todas las declaraciones require e include en todo el plugin:

grep -rn "require\|include" includes/

image.png

Los resultados de la búsqueda devolvieron muchas llamadas require/include. Revisándolas, la mayoría eran llamadas include_once en banner/misc.php y banner/views/index.php — pertenecen al código de renderizado de la interfaz de administración con rutas codificadas, lo que las hace no explotables.

Sin embargo, 2 líneas en backup-heart.php llamaron mi atención:

includes/backup-heart.php:64:   define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');
includes/backup-heart.php:118:  require_once BMI_INCLUDES . '/bypasser.php';

La línea 118 usa require_once con la constante BMI_INCLUDES — si esta constante estuviera codificada, sería segura. Pero mirando hacia arriba, en la línea 64, vi que BMI_INCLUDES se construye a partir de otra constante, BMI_ROOT_DIR. Así que necesitamos rastrear más allá: ¿dónde se le asigna su valor a BMI_ROOT_DIR?

Usé grep nuevamente para rastrearlo:

grep -n "BMI_ROOT_DIR" includes/backup-heart.php

Resultados:

image.png

Line 62: define('BMI_ROOT_DIR', $fields['content-dir']);
Line 64: define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');

La línea 62 muestra que BMI_ROOT_DIR toma su valor de $fields['content-dir']. Esta es una variable, no un valor fijo — necesitamos abrir el archivo y ver qué contiene $fields.

Paso 2: Inspeccionar el código fuente — ¿De dónde viene $fields?

Abrí backup-heart.php en VS Code en la línea 62:

// Line 62
define('BMI_ROOT_DIR', $fields['content-dir']);

// Line 64
define('BMI_INCLUDES', BMI_ROOT_DIR. 'includes');

image.png

Es claramente visible que $fields['content-dir'] va directamente a define(). Ahora necesitamos determinar dónde se asigna la variable $fields:

// Lines 7-9: Only checks POST method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit;
}

// Lines 30-33: Reads ALL HTTP headers from the request
if (isFunctionEnabled('getallheaders')) {
    $fields= getallheaders();
}

// Lines 42-46: Lowercases header names
foreach ($fieldsas $key=> $value) {
    $buffer= $value;
    unset($fields[$key]);
    $fields[strtolower($key)] = $value;
}

image.png

image.png

En este punto, la causa raíz queda completamente clara: $fields contiene todas las cabeceras HTTP obtenidas mediante getallheaders() — completamente controladas por el cliente. No hay wp_verify_nonce(), ni current_user_can(), ni comprobación de ruta válida — simplemente verifica el método POST y lee las cabeceras directamente.

Paso 3: Resumen del flujo de ataque

Attacker sends POST request with header Content-Dir: /path/to/attacker/
    ↓
getallheaders() reads raw headers → $fields['content-dir'] = "/path/to/attacker/"
    ↓
define('BMI_ROOT_DIR', "/path/to/attacker/")   ← no validation
    ↓
define('BMI_INCLUDES', "/path/to/attacker/includes")
    ↓
require_once "/path/to/attacker/includes/bypasser.php"   ← executes PHP
    ↓
Attacker code runs with www-data privileges → RCE

Resumen de la causa raíz: Cabecera HTTP → define() → require_once(), con cero pasos de validación en el medio.

Paso 4: Depuración con Xdebug

Usé Xdebug + VS Code para confirmar visualmente el flujo del ataque. Establecí 2 puntos de interrupción en las líneas 62 y 118 de backup-heart.php y luego envié la solicitud de explotación usando curl.

Punto de interrupción 1 — Línea 62:

El depurador se detuvo justo en define('BMI_ROOT_DIR', $fields['content-dir']). Al expandir la variable $fields en el panel de Variables se mostró un array de 22 elementos — que contenía todas las cabeceras HTTP enviadas por el cliente. Específicamente:

Descargar herramienta