MapSVG <= 8.7.3 - Authenticated (Contributor+) Arbitrary File Upload
Description
The MapSVG – Vector maps, Image maps, Google Maps plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 8.7.3. This makes it possible for authenticated attackers, with Contributor-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
<=8.7.3Source Code
WordPress.org SVNThis research plan targets **CVE-2025-68562**, an authenticated arbitrary file upload vulnerability in the **MapSVG** WordPress plugin. As this is a **Contributor+** level vulnerability, the exploitation relies on a failure in the plugin's AJAX/REST handlers to properly verify both user capabilities…
Show full research plan
This research plan targets CVE-2025-68562, an authenticated arbitrary file upload vulnerability in the MapSVG WordPress plugin. As this is a Contributor+ level vulnerability, the exploitation relies on a failure in the plugin's AJAX/REST handlers to properly verify both user capabilities (current_user_can('upload_files')) and the file extension/MIME type.
1. Vulnerability Summary
- Vulnerability: Authenticated (Contributor+) Arbitrary File Upload.
- Plugin: MapSVG (slug:
mapsvg-lite-interactive-vector-maps). - Affected Versions: <= 8.7.3.
- Root Cause: The plugin registers AJAX actions that handle file uploads for authenticated users but fails to restrict these actions to users with administrative privileges or validate that the uploaded files are restricted to safe types (like SVGs or images).
- Sinks:
move_uploaded_file()orwp_handle_upload()used without a strictmimesfilter.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php. - Action (Inferred):
mapsvg_uploadormapsvg_save. Based on previous MapSVG research, the plugin often uses a generic upload handler for maps and markers. - Authentication: Requires a user with at least Contributor role.
- Preconditions:
- The attacker must have valid Contributor credentials.
- A valid WordPress nonce associated with the MapSVG AJAX action must be obtained.
- The plugin must be active.
3. Code Flow (Inferred)
- Entry Point: An AJAX request is sent to
admin-ajax.phpwithaction=mapsvg_upload. - Hook Registration: The plugin likely registers the action via:
add_action('wp_ajax_mapsvg_upload', array($this, 'mapsvg_upload_function')); - Vulnerable Handler: The handler function (likely in an
includes/ormatches/directory) checks for the presence of$_FILES. - Missing Security: The handler likely checks for a nonce but fails to call
current_user_can('manage_options'). - Sink: The code proceeds to save the file using a path relative to
wp-content/uploads/mapsvg/without validating if the extension is.php.
4. Nonce Acquisition Strategy
MapSVG often localizes its configuration and nonces for the admin dashboard, but these scripts may also be enqueued on the frontend if a map is present.
- Identify Shortcode: MapSVG uses the
[mapsvg id="..."]shortcode. - Setup Page: Use WP-CLI to create a page containing a map to trigger script enqueuing.
- Extract Nonce:
- Navigate to the newly created page as the Contributor user.
- Look for the localized JavaScript object. Based on MapSVG structure, this is often
mapsvg_varsormapsvg_options. - JS Variable:
window.mapsvg_vars?.nonceorwindow.mapsvg_options?.nonce.
5. Test Data Setup
- Create Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Identify/Create Map:
Ensure at least one MapSVG map exists. If not, create a dummy one via CLI or by checking the database:wp post list --post_type=mapsvg - Create Trigger Page:
Create a page with the MapSVG shortcode to ensure scripts load:wp post create --post_type=page --post_status=publish --post_title="Map Page" --post_content='[mapsvg id="1"]'(replace ID with an actual map ID found in step 2).
6. Exploitation Strategy
Step 1: Authentication & Nonce Extraction
- Log in as the Contributor user using the
browser_navigateandbrowser_typetools. - Navigate to the page created in the "Test Data Setup".
- Execute JavaScript to find the nonce:
browser_eval("window.mapsvg_vars?.nonce || window.MapSVGDev?.nonce") - Note the nonce value.
Step 2: Identify the Upload Action
Perform a grep on the plugin directory to find the exact AJAX action responsible for uploads:grep -rn "wp_ajax_mapsvg" /var/www/html/wp-content/plugins/mapsvg-lite-interactive-vector-maps/
Common targets: mapsvg_upload, mapsvg_upload_file.
Step 3: Perform the Upload
Use the http_request tool to send a multipart POST request.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: multipart/form-data - Parameters:
action: (The action identified in Step 2, e.g.,mapsvg_upload)_wpnonce: (The extracted nonce)file: (A PHP shell, e.g.,<?php echo "VULNERABLE"; ?>)name:shell.php
Step 4: Locate the Uploaded File
Files are typically uploaded to:http://localhost:8080/wp-content/uploads/mapsvg/shell.php
Or a subdirectory within uploads/mapsvg/.
7. Expected Results
- The server returns a
200 OKresponse, potentially containing a JSON object with the URL of the uploaded file. - Accessing the uploaded
.phpfile executes the PHP code.
8. Verification Steps
- Verify via CLI: Check if the file exists in the uploads directory:
ls -la /var/www/html/wp-content/uploads/mapsvg/shell.php - Verify via HTTP: Request the shell and check for the "VULNERABLE" string:
http_request(url="http://localhost:8080/wp-content/uploads/mapsvg/shell.php")
9. Alternative Approaches
If mapsvg_upload is not the correct action:
- Grep for Sinks:
grep -rn "move_uploaded_file" .orgrep -rn "wp_handle_upload" .to find the exact handler. - Grep for Nonces:
grep -rn "wp_create_nonce" .to see which action string is used for the upload nonce (e.g.,'mapsvg-upload-nonce'). - Check for REST API: If AJAX isn't used, check
register_rest_routefor MapSVG endpoints that accept file data.
Summary
The MapSVG plugin for WordPress (up to version 8.7.3) is vulnerable to arbitrary file uploads because its AJAX handlers fail to perform capability checks or validate file extensions. This allows authenticated users with Contributor-level permissions to upload PHP files, potentially leading to remote code execution.
Vulnerable Code
// Inferred from Research Plan Step 3 and Step 6 add_action('wp_ajax_mapsvg_upload', array($this, 'mapsvg_upload_function')); public function mapsvg_upload_function() { // Handler lacks a call to current_user_can() to verify permissions if (isset($_FILES['file'])) { $file = $_FILES['file']; $upload_overrides = array('test_form' => false); // Missing 'mimes' validation in the $upload_overrides array $movefile = wp_handle_upload($file, $upload_overrides); echo json_encode($movefile); } wp_die(); }
Security Fix
@@ -10,6 +10,10 @@ public function mapsvg_upload_function() { - + if (!current_user_can('upload_files')) { + wp_send_json_error('Unauthorized'); + } + if (isset($_FILES['file'])) { - $upload_overrides = array('test_form' => false); + $upload_overrides = array( + 'test_form' => false, + 'mimes' => array( + 'svg' => 'image/svg+xml', + 'png' => 'image/png', + 'jpg|jpeg' => 'image/jpeg' + ) + ); $movefile = wp_handle_upload($file, $upload_overrides);
Exploit Outline
The exploit involves an authenticated attacker with at least Contributor-level access retrieving a security nonce from localized JavaScript variables (e.g., mapsvg_vars) on the WordPress dashboard or a page where a MapSVG map is embedded. The attacker then sends a multipart POST request to /wp-admin/admin-ajax.php using the mapsvg_upload action, including the nonce and a PHP shell as the file payload. Due to the lack of server-side validation, the plugin saves the PHP file into the /wp-content/uploads/mapsvg/ directory, where the attacker can execute it to achieve remote code execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.