
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - مصادق عليه (مدير+) رفع ملف تعسفي
يحتوي إضافة ووردبريس Alex Reservations (الإصدارات 2.2.3 والإصدارات الأقدم) على ثغرة رفع ملفات تعسفي تسمح لمسؤولي ووردبريس المصادق عليهم برفع ملفات PHP خبيثة إلى الخادم، مما قد يؤدي إلى تنفيذ تعليمات برمجية عن بُعد.
تم توفير إثبات مفهوم CVE-2025-12399.py لتوضيح قيام مهاجم عن بُعد برفع shell.php وتنفيذ تعليمات برمجية عن بُعد:
python3 ./CVE-2025-12399.py https://TARGETSITE.com admin "$PASSWORD"
[+] Target: http://TARGETSITE.com
[+] Username: admin
[+] Nonce obtained: 022b25d0a5
[+] File uploaded successfully!
[+] Shell URL: https://TARGETSITE.com/wp-content/uploads/alex-reservations/2025/10/shell.php
[+] Command output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
توجد الثغرة في ملف UploadFileController.php عند نقطة النهاية /wp-json/srr/v1/app/upload/file. تفتقر وظيفة الرفع إلى التحقق السليم من الملفات، وتقوم فقط بتنظيف أساسي لاسم الملف باستخدام نمط regex. وهذا يسمح لمسؤولي ووردبريس المصادق عليهم برفع ملفات اعتباطية، بما في ذلك ملفات PHP التي يمكن تنفيذها على الخادم.
المصدر: إدخال المستخدم من $_FILES['file'] (السطر 13)
المُستقبل (Sink): copy($file['tmp_name'], $target_dir_file) (السطر 38)
تحدث الثغرة للأسباب التالية:
routes.php.UploadFileController يرث من الصف الأساسي Controller.$_FILES['file'] تُعالج مباشرة دون تحقق.preg_replace('/[^a-z0-9_\.\-[:space:]]/i', '_', $file_name) (السطر 50)wp-content/uploads/alexr-uploads/YYYY/MM/ دون التحقق من نوع MIME أو فرض قيود على امتدادات الملفات.public function upload(Request $request)
{
$file = $_FILES['file']; // SOURCE: User input ([line 13](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L13))
// Target dir / url
$upload_dir = wp_upload_dir();
$date = evavel_date_now()->format('Y/m');
$base_dir = $upload_dir['basedir'].'/'.ALEXR_UPLOAD_FOLDER.'/'.$date;
$base_url = $upload_dir['baseurl'].'/'.ALEXR_UPLOAD_FOLDER.'/'.$date;
if (!file_exists($base_dir)) {
$folder_created = wp_mkdir_p($base_dir);
if (!$folder_created) {
return $this->response([
'success' => false,
'error' => __eva('Error creating folder.')
]);
}
}
$file_name = $file['name'];
$file_name = preg_replace('/[^a-z0-9_\.\-[:space:]]/i', '_', $file_name); // Only basic sanitization ([line 50](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L50))
$target_dir_file = $base_dir.'/'.$file_name;
$target_url_file = $base_url.'/'.$file_name;
$result = copy($file['tmp_name'], $target_dir_file); // SINK: Direct file copy ([line 38](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L38))
if (!$result) {
return $this->response([
'success' => false,
'error' => __eva('Error saving file.')
]);
}
return $this->response([
'success' => true,
'file_path' => $target_dir_file,
'file_url' => $target_url_file,
'message' => __eva('Uploaded.')
]);
}