
Kalrav AI Agent <= 2.3.3 - Неавторизованная произвольная загрузка файлов через AJAX-действие kalrav_upload_file
Плагин WordPress Kalrav AI Agent (версия 2.3.3 и ниже) содержит уязвимость произвольной загрузки файлов, которая позволяет неаутентифицированным пользователям загружать вредоносные PHP-файлы на сервер, что может привести к удаленному выполнению кода.
Предоставлен POC CVE-2025-13374.py для демонстрации удаленной атаки: загрузка shell.php и выполнение удаленного кода:
python3 ./CVE-2025-13374.py http://techcorp.cc
[+] Target: http://techcorp.cc
[+] File uploaded successfully!
[+] Shell URL: http://techcorp.cc/wp-content/plugins/kalrav-ai-agent/uploads/1763247725-shell.php
[+] Command output:
www-data
Уязвимость существует в функции kalrav_upload_file() на конечной точке . Функциональность загрузки не имеет надлежащей проверки файлов, верификации nonce и проверки прав доступа. Это позволяет неаутентифицированным пользователям загружать произвольные файлы, включая PHP-файлы, которые могут быть выполнены на сервере.
/wp-admin/admin-ajax.phpИсточник: Пользовательский ввод из $_FILES['file'] (строка 978)
Приёмник: move_uploaded_file($_FILES['file']['tmp_name'], $target_path) (строка 982)
Уязвимость возникает из-за:
wp_ajax_nopriv_kalrav_upload_file (строка 967), что позволяет неаутентифицированный доступ.wp_ajax_nopriv_ делает функцию доступной для неаутентифицированных пользователей.$_FILES['file'], обрабатываются напрямую без проверки.basename(): time() . '-' . basename($_FILES['file']['name']) (строка 979), которая предотвращает только обход каталогов, но не проверяет расширения файлов.wp-content/plugins/kalrav-ai-agent/uploads/.Файл: kalrav-ai-agent.php
Строки: 969-996
add_action('wp_ajax_kalrav_upload_file', 'kalrav_upload_file');
add_action('wp_ajax_nopriv_kalrav_upload_file', 'kalrav_upload_file');
function kalrav_upload_file()
{
// Path to your plugin uploads folder
$upload_dir = plugin_dir_path(__FILE__) . 'uploads/';
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
if (!empty($_FILES['file']['name'])) {
$file_name = time() . '-' . basename($_FILES['file']['name']);
$target_path = $upload_dir . $file_name;
if (move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
wp_send_json_success([
'message' => 'File uploaded successfully!',
'file_path' => $target_path,
'url' => plugins_url('uploads/' . $file_name, __FILE__)
]);
} else {
wp_send_json_error(['message' => 'Failed to move uploaded file.']);
}
} else {
wp_send_json_error(['message' => 'No file uploaded.']);
}
wp_die();
}