
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Upload Arbitrário de Arquivo Autenticado (Admin+)
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Upload Arbitrário de Arquivos Autenticado (Admin+)
O plugin Alex Reservations do WordPress (versões 2.2.3 e anteriores) contém uma vulnerabilidade de upload arbitrário de arquivos que permite que administradores autenticados do WordPress enviem arquivos PHP maliciosos para o servidor, potencialmente levando à execução remota de código.
Um POC CVE-2025-12399.py é fornecido para demonstrar um atacante remoto enviando shell.php e executando código 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)
A vulnerabilidade existe no arquivo UploadFileController.php, no endpoint /wp-json/srr/v1/app/upload/file. A funcionalidade de upload não possui validação adequada de arquivos e executa apenas uma sanitização básica do nome do arquivo usando um padrão de regex. Isso permite que administradores autenticados do WordPress enviem arquivos arbitrários, incluindo arquivos PHP que podem ser executados no servidor.
Origem: Entrada do usuário a partir de $_FILES['file'] (linha 13)
Sumidouro: copy($file['tmp_name'], $target_dir_file) (linha 38)
A vulnerabilidade ocorre porque:
routes.php.UploadFileController estende o Controller base.$_FILES['file'] são processados diretamente, sem validação.preg_replace('/[^a-z0-9_\.\-[:space:]]/i', '_', $file_name) (linha 50)wp-content/uploads/alexr-uploads/YYYY/MM/ sem validação do tipo MIME ou restrições de extensão de arquivo.Arquivo: includes/application/Alexr/Http/Controllers/UploadFileController.php
Linhas: 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.')
]);
}