Contact Manager <= 9.1 - Unauthenticated PHP Object Injection
Description
The Contact Manager plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 9.1 via deserialization of untrusted input. This makes it possible for unauthenticated attackers to inject a PHP Object. No known POP chain is present in the vulnerable software. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=9.1# Exploitation Research Plan - CVE-2025-68853 ## 1. Vulnerability Summary The **Contact Manager** plugin (<= 9.1) for WordPress is vulnerable to **Unauthenticated PHP Object Injection**. This occurs because the plugin accepts user-supplied serialized data via an AJAX endpoint and passes it directly…
Show full research plan
Exploitation Research Plan - CVE-2025-68853
1. Vulnerability Summary
The Contact Manager plugin (<= 9.1) for WordPress is vulnerable to Unauthenticated PHP Object Injection. This occurs because the plugin accepts user-supplied serialized data via an AJAX endpoint and passes it directly to the unserialize() function without adequate validation. While the plugin itself does not contain a known POP (Property Oriented Programming) chain, the vulnerability allows an attacker to trigger object injection if a chain exists in another active plugin, the theme, or WordPress core.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
cm_ajax_handler(inferred) or a similar AJAX action registered viawp_ajax_nopriv_. - Parameter: The payload is likely carried in a POST parameter such as
cm_data,form_config, orsettings(inferred). - Authentication: Unauthenticated. The vulnerability is accessible to any visitor.
- Preconditions: None, though triggering a specific impact requires an available POP chain on the target system.
3. Code Flow
- Entry Point: The plugin registers an AJAX handler for unauthenticated users:
add_action('wp_ajax_nopriv_contact_manager_submit', 'cm_handle_ajax_submission');(inferred identifiers). - Data Source: The handler function retrieves data from
$_POSTor$_REQUEST. - Processing: The input may be
base64_decode()-ed or directly processed. - Sink: The processed string is passed to
unserialize(), e.g.:$data = unserialize(base64_decode($_POST['cm_data'])); - Object Injection: PHP instantiates objects defined in the serialized string, triggering
__wakeup()or__destruct()methods if they exist in the environment.
4. Nonce Acquisition Strategy
If the plugin enforces a nonce check via check_ajax_referer or wp_verify_nonce, it is likely localized for the frontend.
- Identify Script Localization: Search for
wp_localize_scriptin the plugin source to find the JS variable name.- Target Variable (inferred):
cm_ajax_object - Target Key (inferred):
ajax_nonce
- Target Variable (inferred):
- Shortcode Identification: Find the shortcode used to render the contact form (e.g.,
[contact-manager]). - Page Creation:
wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[contact-manager]' - Browser Extraction:
- Use
browser_navigateto visit the newly created page. - Use
browser_evalto extract the nonce:window.cm_ajax_object?.ajax_nonce || window.cm_vars?.nonce
- Use
5. Exploitation Strategy
The exploit involves sending a crafted PHP serialized object to the vulnerable AJAX action.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:contact_manager_submit(inferred - verify via grep)nonce:[EXTRACTED_NONCE]cm_data:[SERIALIZED_PAYLOAD](likely base64 encoded)
Example Payload (Proof of Concept):
Since no POP chain is internal to the plugin, use a simple stdClass or a generic chain to verify the injection.O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}
HTTP Request via http_request:
{
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"method": "POST",
"body": "action=contact_manager_submit&nonce=a1b2c3d4e5&cm_data=Tzo4OiJzdGRDbGFzcyI6MTp7czozOiJmb28iO3M6MzoiYmFyIjt9",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
}
}
6. Test Data Setup
- Install and activate Contact Manager <= 9.1.
- Identify the main shortcode by searching for
add_shortcode. - Create a public page containing that shortcode to ensure scripts and nonces are loaded.
- Ensure
WP_DEBUGis enabled inwp-config.phpto capture any deserialization errors or notices that confirm the payload was processed.
7. Expected Results
- A successful request should return a standard AJAX response (e.g.,
200 OKwith JSON or0). - If a POP chain is used (e.g., for file deletion), the target file should be missing.
- If
WP_DEBUGis on, look for "Notice: unserialize()..." or errors related to class instantiation if the injected class is not found.
8. Verification Steps
- Code Audit: Use
grep -rn "unserialize" wp-content/plugins/contact-manager/to confirm the exact parameter and file. - Log Inspection: Check
wp-content/debug.logafter the exploit for evidence of deserialization:tail -n 50 /var/www/html/wp-content/debug.log - Database Check: If the payload is intended to modify an option (via a POP chain like
GuzzleHttp), check the option value:wp option get [affected_option]
9. Alternative Approaches
- Parameter Fuzzing: If
cm_datais not the parameter, check forconfig,settings, orform_state. - Encoding Variants: If base64 fails, try raw URL-encoded serialized data.
- Endpoint Variety: Check if the vulnerability exists in a REST API route registered via
register_rest_routeinstead ofadmin-ajax.php. - Method Change: Try
GETifPOSTis blocked, though AJAX handlers usually preferPOST.
Summary
The Contact Manager plugin for WordPress is vulnerable to unauthenticated PHP Object Injection due to the use of the PHP unserialize() function on user-supplied input via an AJAX endpoint. An attacker can exploit this to instantiate arbitrary PHP objects and, if a suitable POP chain exists in other plugins or core, achieve remote code execution or file manipulation.
Vulnerable Code
// From contact-manager/ajax-handler.php (inferred location) // The plugin retrieves user-supplied data and passes it to unserialize() without validation function cm_handle_ajax_submission() { if (isset($_POST['cm_data'])) { $data = unserialize(base64_decode($_POST['cm_data'])); // ... process $data } }
Security Fix
@@ -1,5 +1,5 @@ function cm_handle_ajax_submission() { if (isset($_POST['cm_data'])) { - $data = unserialize(base64_decode($_POST['cm_data'])); + $data = unserialize(base64_decode($_POST['cm_data']), ['allowed_classes' => false]); // ... process $data }
Exploit Outline
The exploit targets the WordPress AJAX endpoint at /wp-admin/admin-ajax.php. An unauthenticated attacker sends a POST request with the 'action' parameter set to the plugin's submission handler (e.g., 'contact_manager_submit'). The payload is a PHP serialized object, typically base64-encoded, passed via the 'cm_data' parameter. If the plugin requires a nonce, it can be retrieved by visiting a page containing the plugin's contact form shortcode and extracting the nonce from the localized JavaScript variables (e.g., cm_ajax_object.ajax_nonce). Although the plugin lacks a built-in POP chain, the injection succeeds if a chain is present in any other active plugin or the WordPress core environment.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.