Easy Voice Mail <= 1.2.5 - Unauthenticated Stored Cross-Site Scripting via 'message'
Description
The Easy Voice Mail plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the ‘message’ parameter in all versions up to, and including, 1.2.5 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=1.2.5This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the **Easy Voice Mail** plugin (<= 1.2.5). The vulnerability allows unauthenticated users to inject malicious scripts into the `message` parameter of a voicemail submission, which is then executed in the context of an ad…
Show full research plan
This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the Easy Voice Mail plugin (<= 1.2.5). The vulnerability allows unauthenticated users to inject malicious scripts into the message parameter of a voicemail submission, which is then executed in the context of an administrator viewing the voicemail in the WordPress dashboard.
1. Vulnerability Summary
- Vulnerability: Stored Cross-Site Scripting (XSS)
- Vulnerable Parameter:
message - Plugin Slug:
easy-voice-mail - Affected Versions: <= 1.2.5
- Sink: The admin-facing "Messages" or "Inbox" page where voicemails are displayed.
- Cause: The plugin fails to sanitize the
messageinput during submission and fails to escape it during output in the administrative interface.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
evm_save_messageorevm_send_message(inferred from typical plugin naming conventions; to be verified in source). - Authentication: Unauthenticated (
wp_ajax_nopriv_hook). - Payload Location: The
messagePOST parameter. - Preconditions: A page or post must contain the Easy Voice Mail shortcode (likely
[easy-voice-mail]) to provide the necessary nonce and environment for the AJAX request.
3. Code Flow (Inferred)
- Entry Point: An unauthenticated user accesses a public page containing the voicemail recording interface.
- Input: The user completes a "recording" or "submission" process. The frontend JS sends an AJAX request to
admin-ajax.phpwith anaction(e.g.,evm_save_voicemail) and themessageparameter. - Processing: The PHP handler (e.g.,
save_message_callback) receives$_POST['message']. It likely saves this data to the database (either a custom table like{$wpdb->prefix}evm_messagesor as a custom post typeevm_message) without callingsanitize_text_field()orwp_kses(). - Storage: The payload
<script>alert(document.domain)</script>is stored raw in the database. - Sink: An administrator logs in and navigates to the "Easy Voice Mail" management page (e.g.,
wp-admin/admin.php?page=easy-voice-mail-messages). - Execution: The admin page retrieves the messages and outputs the
messagecontent directly:echo $message_data->message;without usingesc_html().
4. Nonce Acquisition Strategy
The plugin likely uses wp_localize_script to pass a nonce and the AJAX URL to the frontend.
- Identify Shortcode: Search the plugin source for
add_shortcode.- Search command:
grep -rn "add_shortcode" .
- Search command:
- Create Test Page: Create a public page containing the identified shortcode.
- Command:
wp post create --post_type=page --post_status=publish --post_title="Voicemail" --post_content='[easy-voice-mail]'(assuming the slug).
- Command:
- Navigate and Extract: Use
browser_navigateto visit the new page. - Variable Extraction: Use
browser_evalto find the localization object. Look forevm_ajax,evm_settings, or similar.- Likely JS path:
window.evm_settings?.nonceorwindow.evm_ajax_obj?.nonce. - Search command for variable:
grep -rn "wp_localize_script" .to find the object name and key.
- Likely JS path:
5. Exploitation Strategy
- Setup: Install the plugin version 1.2.5. Create an admin user and a public page with the shortcode.
- Nonce Retrieval:
- Navigate to the public page.
- Extract the nonce via
browser_eval.
- Payload Delivery:
- Use
http_requestto send a POST request to/wp-admin/admin-ajax.php. - Method: POST
- Content-Type:
application/x-www-form-urlencoded - Body:
action=evm_save_message&nonce=[EXTRACTED_NONCE]&message=<script>alert('XSS')</script>&name=Attacker&email=attacker@example.com - Note: The exact
actionand parameter names (name,email) must be verified by greppingadd_action( 'wp_ajax_nopriv_...in the plugin code.
- Use
- Triggering: Navigate to the plugin's message list in the admin dashboard using
browser_navigateas the administrator.
6. Test Data Setup
- Plugin: Easy Voice Mail v1.2.5.
- Page: A published page with the
[easy-voice-mail](or correct slug) shortcode. - Admin User: Pre-authenticated session for the PoC agent to verify the execution.
7. Expected Results
- The AJAX submission should return a success status (e.g.,
{"success":true}or1). - When the admin dashboard page is loaded, a JavaScript alert should trigger, or the script tag should be visible in the raw HTML source of the message list page.
8. Verification Steps
- Database Check: Use WP-CLI to check if the message was stored:
- Command:
wp db query "SELECT * FROM wp_evm_messages;"(adjust table name if it uses post meta).
- Command:
- HTML Source Check: Use
http_requestas an admin to fetch the message list page and grep for the payload.- Command: Check if
<script>alert('XSS')</script>appears unencoded in the response body.
- Command: Check if
9. Alternative Approaches
- Post Meta Sink: If the plugin stores messages as Custom Post Types, the XSS might trigger on the
edit.php?post_type=evm_messagescreen or inside the Gutenberg editor when the admin opens the specific "voicemail" post. - Email Sink: If the plugin sends an email notification to the admin with the message content, the XSS could trigger in webmail clients that do not sanitize HTML (less likely to be the primary CVSS vector but a valid impact).
- Direct Post: If the AJAX handler doesn't check nonces (or uses the default
-1), the attack is even simpler. Check the handler forcheck_ajax_refererorwp_verify_nonce.
Summary
The Easy Voice Mail plugin for WordPress (up to version 1.2.5) is vulnerable to Stored Cross-Site Scripting (XSS) via the 'message' parameter. Due to a lack of input sanitization and output escaping, unauthenticated users can submit voicemail messages containing malicious JavaScript that will execute in the browser of an administrator viewing the messages in the WordPress dashboard.
Exploit Outline
1. Identify a public page or post containing the Easy Voice Mail submission shortcode (typically `[easy-voice-mail]`). 2. Extract the necessary AJAX nonce and endpoint information from the page source, usually found in a localized script object like `evm_settings` or `evm_ajax_obj`. 3. Send an unauthenticated POST request to `/wp-admin/admin-ajax.php` using the identified AJAX action (e.g., `evm_save_message`). 4. Set the `message` POST parameter to a JavaScript payload, such as `<script>alert(document.cookie)</script>`, along with the required nonce and any other mandatory fields (e.g., name, email). 5. As an administrator, navigate to the plugin's message management or inbox page in the WordPress dashboard. The stored script will execute when the malicious message is rendered on the screen.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.