
Kalrav AI Agent <= 2.3.3 - kalrav_upload_file AJAX Action을 통한 인증되지 않은 임의 파일 업로드
워드프레스 Kalrav AI Agent 플러그인(버전 2.3.3 및 이전 버전)에는 인증되지 않은 사용자가 서버에 악성 PHP 파일을 업로드하여 원격 코드 실행으로 이어질 수 있는 임의 파일 업로드 취약점이 있습니다.
원격 공격자가 shell.php를 업로드하고 원격 코드를 실행하는 과정을 보여주는 POC CVE-2025-13374.py가 제공됩니다:
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
이 취약점은 /wp-admin/admin-ajax.php 엔드포인트의 kalrav_upload_file() 함수에 존재합니다. 업로드 기능에는 적절한 파일 검증, 논스(nonce) 검증, 권한 검사가 부재합니다. 이를 통해 인증되지 않은 사용자가 서버에서 실행될 수 있는 PHP 파일을 포함한 임의의 파일을 업로드할 수 있습니다.
소스: $_FILES['file']의 사용자 입력 (line 978)
싱크: move_uploaded_file($_FILES['file']['tmp_name'], $target_path) (line 982)
취약점은 다음과 같은 이유로 발생합니다:
wp_ajax_nopriv_kalrav_upload_file 훅(line 967)을 통해 등록되어 인증되지 않은 접근을 허용합니다.wp_ajax_nopriv_ 접두사 덕분에 인증되지 않은 사용자가 함수에 접근할 수 있습니다.$_FILES['file']의 사용자 제어 파일 데이터가 검증 없이 직접 처리됩니다.basename()을 사용한 기본적인 파일명 정화만 적용됩니다: time() . '-' . basename($_FILES['file']['name']) (line 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();
}