Backup Migration <= 2.0.0 - Missing Authorization to Unauthenticated Backup Upload to Offline Storage
Description
The Backup Migration plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 2.0.0. This is due to a missing capability check on the 'initializeOfflineAjax' function and lack of proper nonce verification. The endpoint only validates against hardcoded tokens which are publicly exposed in the plugin's JavaScript. This makes it possible for unauthenticated attackers to trigger the backup upload queue processing, potentially causing unexpected backup transfers to configured cloud storage targets and resource exhaustion.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LTechnical Details
What Changed in the Fix
Changes introduced in v2.1.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14944 (Backup Migration) ## 1. Vulnerability Summary The **Backup Migration** plugin (up to 2.0.0) contains a Missing Authorization vulnerability in its offline storage handling logic. The function `initializeOfflineAjax` is registered as an unauthenticated AJ…
Show full research plan
Exploitation Research Plan: CVE-2025-14944 (Backup Migration)
1. Vulnerability Summary
The Backup Migration plugin (up to 2.0.0) contains a Missing Authorization vulnerability in its offline storage handling logic. The function initializeOfflineAjax is registered as an unauthenticated AJAX action (wp_ajax_nopriv_...) but fails to implement a current_user_can() capability check or a standard WordPress nonce verification. Instead, it relies on a "token" that is hardcoded or generated and then exposed to all users through localized JavaScript variables. This allows an unauthenticated attacker to trigger backup upload queue processing, leading to resource exhaustion or unauthorized data transfers to configured cloud storage.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
bmi_initialize_offline_backup(triggers theinitializeOfflineAjaxfunction). - Required Parameter:
token(The "offline token"). - Authentication: Unauthenticated (No login required).
- Preconditions: The plugin must be active. Some cloud/offline storage configuration may need to be present for the upload to actually "exhaust resources," but the trigger itself is the vulnerability.
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwithaction=bmi_initialize_offline_backup. - Hook Registration: The plugin registers the action (inferred location:
includes/backup-methods/offline/offline.phporincludes/initializer.php):add_action('wp_ajax_bmi_initialize_offline_backup', 'initializeOfflineAjax'); add_action('wp_ajax_nopriv_bmi_initialize_offline_backup', 'initializeOfflineAjax'); - Vulnerable Function: The
initializeOfflineAjaxfunction executes. - Token Validation: It checks if
$_POST['token']matches a value stored in the database (or a hardcoded one). - Localization: This same token is made available to the frontend JS via
wp_localize_script:wp_localize_script('bmi-backup-js', 'bmi_ajax_var', array( 'bmi_offline_token' => $offline_token, // ... )); - Execution: If the token matches, it proceeds to call methods that process the backup upload queue without checking if the requester is an administrator.
4. Token Acquisition Strategy
Nonces are not used here, but a "token" is. The token is exposed in the bmi_ajax_var global JavaScript object.
- Navigate: Use
browser_navigateto the WordPress homepage or any page where the plugin might load. - Identification: The plugin typically enqueues its main JS on all admin pages and sometimes on the frontend if certain features are enabled.
- JS Evaluation:
- Execute:
browser_eval("window.bmi_ajax_var?.bmi_offline_token") - If
bmi_ajax_varis not found on the frontend, check for other common localization objects likeBMI_CONF.
- Execute:
- Bypass Check: If the code validates against a hardcoded string (e.g., the literal string
"BMI_OFFLINE_TOKEN"), try that as the token value directly.
5. Exploitation Strategy
Step 1: Discover the Token
Navigate to the site and extract the token from the global JS context.
- URL:
{{BASE_URL}} - Script:
window.bmi_ajax_var.bmi_offline_token
Step 2: Trigger the Offline Backup Upload
Send the unauthenticated AJAX request.
- Method:
POST - URL:
{{BASE_URL}}/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=bmi_initialize_offline_backup&token=[EXTRACTED_TOKEN]
6. Test Data Setup
- Install Plugin: Ensure Backup Migration <= 2.0.0 is installed and active.
- Configuration (Optional): To observe the "resource exhaustion" or "upload" part, configure a dummy offline/remote storage destination in the plugin settings. However, the success of the AJAX call (returning a success status or triggering the function) is sufficient for a PoC.
7. Expected Results
- Success Response: The server returns a
200 OKresponse, often with a JSON body indicating the backup process or queue has started (e.g.,{"success": true}). - Server Behavior: The server begins processing files or attempting to contact storage providers in the background.
8. Verification Steps
- Check Plugin Logs: If the plugin maintains internal logs (often in
wp-content/uploads/backup-migration/logs/), check for entries timestamped at the time of the exploit indicating "Offline upload started" or "Queue processing triggered." - Monitor Processes: Use
toporpsif possible (within the environment) to see if PHP processes are consuming resources immediately after the request. - WP-CLI Verification: Check the backup status/options:
(Note: The option namewp option get bmi_backup_statusbmi_backup_statusis inferred from standard plugin nomenclature).
9. Alternative Approaches
If bmi_ajax_var is not visible on the frontend:
- Check Admin-Side (if you have any user): Even a low-privileged user might see the token if they can access the dashboard.
- Predictable Token: Check if the token is a predictable hash (e.g.,
md5(get_option('siteurl'))). - Direct Action Guessing: Some versions of the plugin used the literal string
BMI_OFFLINE_TOKENas the token value in the check if none was set. Try:action=bmi_initialize_offline_backup&token=BMI_OFFLINE_TOKEN
Summary
The Backup Migration plugin (<= 2.0.0) contains a missing authorization vulnerability in its backup upload processing logic. Unauthenticated attackers can trigger the backup upload queue by exploiting a lack of capability checks and nonce verification on the 'bmi_initialize_offline_backup' AJAX endpoint, utilizing a token that is exposed in the site's public JavaScript.
Vulnerable Code
// Inferred registration in includes/backup-methods/offline/offline.php or initializer.php add_action('wp_ajax_bmi_initialize_offline_backup', 'initializeOfflineAjax'); add_action('wp_ajax_nopriv_bmi_initialize_offline_backup', 'initializeOfflineAjax'); --- // Inferred localization exposing the token in localized JavaScript variables wp_localize_script('bmi-backup-js', 'bmi_ajax_var', array( 'bmi_offline_token' => $offline_token, // ... ));
Security Fix
@@ -1 +1 @@ -#toplevel_page_backup-migration .wp-menu-image img{padding-top:8px !important} +#toplevel_page_backup-migration .wp-menu-image img{padding-top:8px !important} \ No newline at end of file @@ -1 +1 @@ -@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap");#bmi,#bb-warning-notice{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-family:'Montserrat', Helvetica, Arial, sans-serif;max-width:1495px;max-width:min(1495px, 95%);margin:0 auto;padding-top:55px;min-width:1495px;min-width:calc(min(1495px, 95%))} (truncated)
Exploit Outline
1. Retrieve the Offline Token: Navigate to the target website's frontend and inspect the page source or use the browser console to extract the 'bmi_offline_token' value from the 'bmi_ajax_var' global JavaScript object. 2. Formulate Request: Construct an unauthenticated POST request to the WordPress AJAX endpoint at '/wp-admin/admin-ajax.php'. 3. Payload: Include the following parameters in the request body: 'action=bmi_initialize_offline_backup' and 'token=[EXTRACTED_TOKEN]'. 4. Trigger Upload: Send the request. The server will execute the 'initializeOfflineAjax' function, triggering the backup upload process to configured remote storage without verifying if the requester has administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.