5,000 WordPress Sites Affected by Unauthenticated Remote Code Execution Vulnerability in JS Help Desk WordPress Plugin


📢 Did you know Wordfence runs a Bug Bounty Program for all WordPress plugin and themes at no cost to vendors? Researchers can earn up to $10,400, for all in-scope vulnerabilities submitted to our Bug Bounty Program! Find a vulnerability, submit the details directly to us, and we handle all the rest. 


On July 11th, 2024, we received a submission for an unauthenticated Remote Code Execution vulnerability in JS Help Desk, a WordPress plugin with more than 5,000 active installations. This vulnerability can be leveraged to execute code remotely.

Props to Connor Billings who discovered and responsibly reported this vulnerability through the Wordfence Bug Bounty Program. This researcher earned a bounty of $716.00 for this discovery. Our mission is to Secure the Web, which is why we are investing in quality vulnerability research and collaborating with researchers of this caliber through our Bug Bounty Program. We are committed to making the WordPress ecosystem more secure, which ultimately makes the entire web more secure.

Wordfence Premium, Wordfence Care, and Wordfence Response users received a firewall rule to protect against any exploits targeting this vulnerability on July 25, 2024. Sites using the free version of Wordfence will receive the same protection 30 days later on August 24, 2024.

We contacted the JS Help Desk team on July 25, 2024, and received a response on the same day. After providing full disclosure details, the developer released the first patch on July 29, 2024, and the second patch on August 5, 2024. We would like to commend the JS Help Desk team for their prompt response and timely patch.

We urge users to update their sites with the latest patched version of JS Help Desk, version 2.8.7 at the time of this writing, as soon as possible.

Vulnerability Summary from Wordfence Intelligence

Description: JS Help Desk – The Ultimate Help Desk & Support Plugin <= 2.8.6 – Unauthenticated PHP Code Injection to Remote Code Execution
Affected Plugin: JS Help Desk – The Ultimate Help Desk & Support Plugin
Plugin Slug: js-support-ticket
Affected Versions: <= 2.8.6
CVE ID: CVE-2024-7094
CVSS Score: 9.8 (Critical)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Researcher/s: Connor Billings
Fully Patched Version: 2.8.7
Bounty Award: $716.00

The JS Help Desk – The Ultimate Help Desk & Support Plugin plugin for WordPress is vulnerable to PHP Code Injection leading to Remote Code Execution in all versions up to, and including, 2.8.6 via the ‘storeTheme’ function. This is due to a lack of sanitization on user-supplied values, which replace values in the style.php file, along with missing capability checks. This makes it possible for unauthenticated attackers to execute code on the server. This issue was partially patched in 2.8.6 when the code injection issue was resolved, and fully patched in 2.8.7 when the missing authorization and cross-site request forgery protection was added.

Technical Analysis

The JS Help Desk – The Ultimate Help Desk & Support plugin is designed to provide a seamless and professional helpdesk and support platform to integrate into WordPress.

Examining the code reveals that the plugin uses the checkFormRequest() function in the JSSTformhandler class to handle form requests, which can call any function of the JSST-prefixed controller class.

function checkFormRequest() {
    $formrequest = JSSTrequest::getVar('form_request', 'post');
    if ($formrequest == 'jssupportticket') {
        //handle the request
        $page_id = JSSTRequest::getVar('page_id', 'GET');
        jssupportticket::setPageID($page_id);
        $modulename = (is_admin()) ? 'page' : 'jstmod';
        $module = JSSTrequest::getVar($modulename);
        JSSTincluder::include_file($module);
        $class = 'JSST' . $module . "Controller";
        $task = JSSTrequest::getVar('task');
        $obj = new $class;
        $obj->$task();
    }
}

This can call the savetheme() function in the JSSTthemesController controller class. Although this function is nonce protected, the nonce can unfortunately be obtained by unauthenticated attackers in the vulnerable version.

static function savetheme() {
    $nonce = JSSTrequest::getVar('_wpnonce');
    if (! wp_verify_nonce( $nonce, 'save-theme') ) {
        die( 'Security check Failed' );
    }
    $data = JSSTrequest::get('post');
    JSSTincluder::getJSModel('themes')->storeTheme($data);

The savetheme() function calls the storeTheme() function in the JSSTthemesModel class, which contains the following code snippet:

function storeTheme($data) {
    $filepath = JSST_PLUGIN_PATH . 'includes/css/style.php';
    $filestring = file_get_contents($filepath);
    $this->replaceString($filestring, 1, $data);
    $this->replaceString($filestring, 2, $data);
    $this->replaceString($filestring, 3, $data);
    $this->replaceString($filestring, 4, $data);
    $this->replaceString($filestring, 5, $data);
    $this->replaceString($filestring, 6, $data);
    $this->replaceString($filestring, 7, $data);
    if (file_put_contents($filepath, $filestring)) {
        update_option('jsst_set_theme_colors', json_encode($data));
        JSSTincluder::getJSModel('jssupportticket')->updateColorFile();
        JSSTmessage::setMessage(esc_html(__('The new theme has been applied', 'js-support-ticket')), 'updated');

This code reads the contents of style.php using the file_get_contents() function, then replaces the $color values from the style.php file using the replaceString() function.

function replaceString(&$filestring, $colorNo, $data) {
    if (strstr($filestring, '$color' . $colorNo)) {
        $path1 = jssupportticketphplib::JSST_strpos($filestring, '$color' . $colorNo);
        $path2 = jssupportticketphplib::JSST_strpos($filestring, ';', $path1);
        $filestring = substr_replace($filestring, '$color' . $colorNo . ' = "' . $data['color' . $colorNo] . '";', $path1, $path2 - $path1 + 1);
    }
}

After that, it saves the modifications to the file with the file_put_contents() function. This portion is what makes it possible for unauthenticated attackers to append arbitrary malicious PHP code to the style.php file and thus, when the style.php file is loaded, trigger remote code execution on the server. By default, this file is loaded at the end of the storeTheme() function through the updateColorFile() function in the JSSTjssupportticketModel class.

This updateColorFile() function calls require() on the style.php file and executes any of the code injected into the file.

function updateColorFile(){
    $color = require(JSST_PLUGIN_PATH . 'includes/css/style.php');

As with all remote code execution vulnerabilities, this can lead to complete site compromise through the use of webshells and other techniques.

Wordfence Firewall

The following graphic demonstrates the steps to exploitation an attacker might take and at which point the Wordfence firewall would block an attacker from successfully exploiting the vulnerability.

The Wordfence firewall rule detects the malicious action and blocks the request if it does not come from an existing authorized administrator.

Disclosure Timeline

July 11, 2024 – We received the submission for the Code Injection to Remote Code Execution vulnerability in JS Help Desk via the Wordfence Bug Bounty Program.
July 25, 2024 – We validated the report and confirmed the proof-of-concept exploit.
July 25, 2024 – Wordfence Premium, Care, and Response users received a firewall rule to provide protection against any exploits that may target this vulnerability.
July 25, 2024 – We initiated contact with the plugin vendor asking that they confirm the inbox for handling the discussion.
July 25, 2024 – The vendor confirmed the inbox for handling the discussion.
July 25, 2024 – We sent over the full disclosure details. The vendor acknowledged the report and began working on a fix.
July 29, 2024 – The partially patched version of the plugin, 2.8.6, is released.
August 5, 2024 – The fully patched version of the plugin, 2.8.7, is released.
August 24, 2024 – Wordfence Free users will receive the same protection.

Conclusion

In this blog post, we detailed a Remote Code Execution vulnerability within the JS Help Desk plugin affecting versions 2.8.6 and earlier. This vulnerability allows unauthenticated threat actors to execute malicious code on the server. The vulnerability has been addressed in version 2.8.7 of the plugin.

We encourage WordPress users to verify that their sites are updated to the latest patched version of JS Help Desk as soon as possible considering the critical nature of this vulnerability.

Wordfence Premium, Wordfence Care, and Wordfence Response users received a firewall rule to protect against any exploits targeting this vulnerability on July 25, 2024. Sites using the free version of Wordfence will receive the same protection 30 days later on August 24, 2024.

If you know someone who uses this plugin on their site, we recommend sharing this advisory with them to ensure their site remains secure, as this vulnerability poses a significant risk.

Did you enjoy this post? Share it!

Comments

2 Comments
  • These posts about vulnerabilities are helpful, but what would make them more helpful is showing the changes the plugin makers made to fix the problem. I downloaded the plugin js-support-ticket to see how the new version was different and saw the changes they made to the storeTheme($data) function.
    I see they added a line to make sure that the user had the ability to 'manage_options'. And after that they called a routine to sanitize the data received from the user.
    So on a post like this, showing the before, vulnerable code, and the after, safe code, would be helpful.
    I think these posts are read by many people who code plugins. Showing how the code was fixed would be helpful.

    • Hi Daniel, thank you for the feedback! We'll keep that in mind as we write future posts.