Majestic Support <= 1.1.2 - Missing Authorization
Description
The Majestic Support plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.1.2. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.1.2What Changed in the Fix
Changes introduced in v1.1.3
Source Code
WordPress.org SVN# Majestic Support <= 1.1.2 - Missing Authorization Research Plan ## 1. Vulnerability Summary The **Majestic Support** plugin for WordPress (versions <= 1.1.2) contains a missing authorization vulnerability. The plugin's request handling architecture, primarily managed in `MJTC_ticketController`, r…
Show full research plan
Majestic Support <= 1.1.2 - Missing Authorization Research Plan
1. Vulnerability Summary
The Majestic Support plugin for WordPress (versions <= 1.1.2) contains a missing authorization vulnerability. The plugin's request handling architecture, primarily managed in MJTC_ticketController, relies heavily on WordPress nonces for request validation but lacks sufficient current_user_can() capability checks for state-changing operations. Specifically, certain actions (like deleting attachments or closing tickets) are reachable by unauthenticated visitors because the plugin exposes the necessary nonces on public-facing support pages to facilitate guest ticket functionality.
2. Attack Vector Analysis
- Endpoint: The page containing the
[majesticsupport]shortcode (usually created at/majestic-support-controlpanel/during activation). - Vulnerable Component:
MJTC_ticketController(inmodules/ticket/controller.php) and its interaction withMJTC_attachmentModel(inmodules/attachment/model.php). - Action: Unauthorized deletion of ticket attachments.
- Parameters:
mjsmod: The module name (e.g.,ticketorattachment).mjslay: The layout/action name.majesticsupportid: The ID of the target resource (ticket or attachment).MJTC_nonce: The security nonce.
- Authentication: None required (
Summary
The Majestic Support plugin for WordPress (<= 1.1.2) fails to perform capability or ownership checks on sensitive functions, most notably those handling ticket attachments. Because security nonces are rendered on public-facing support pages to facilitate guest ticket creation, unauthenticated attackers can use these nonces to perform unauthorized actions like downloading or deleting files.
Vulnerable Code
// modules/attachment/model.php @ line 176 function getDownloadAttachmentByName($file_name,$id){ if(empty($file_name)) return false; if(!is_numeric($id)) return false; $filename = MJTC_majesticsupportphplib::MJTC_str_replace(' ', '_',$file_name); $filename = MJTC_majesticsupportphplib::MJTC_clean_file_path($filename); $query = "SELECT attachmentdir FROM `".majesticsupport::$_db->prefix."mjtc_support_tickets` WHERE id = ".esc_sql($id); $foldername = majesticsupport::$_db->get_var($query); $MJTC_datadirectory = majesticsupport::$_config['data_directory']; $maindir = wp_upload_dir(); $path = $maindir['basedir']; $path = $path .'/'.$MJTC_datadirectory; $path = $path . '/attachmentdata'; $path = $path . '/ticket/' . $foldername; $file = $path . '/'.$filename; // ... (omitted: file headers and readfile) ... } --- // modules/attachment/model.php @ line 115 function removeAttachment($id) { if (!is_numeric($id)) return false; $query = $query = "SELECT ticket.attachmentdir AS foldername,ticket.id AS ticketid,attach.filename " . " FROM `".majesticsupport::$_db->prefix."mjtc_support_attachments` AS attach " . " JOIN `".majesticsupport::$_db->prefix."mjtc_support_tickets` AS ticket ON ticket.id = attach.ticketid " . " WHERE attach.id = ". esc_sql($id); $obj = majesticsupport::$_db->get_row($query); $filename = $obj->filename; $foldername = $obj->foldername; $row = MJTC_includer::MJTC_getTable('attachments'); if ($row->delete($id)) { // ... (omitted: physical file deletion) ... } }
Security Fix
@@ -176,35 +176,55 @@ function getDownloadAttachmentByName($file_name,$id){ if(empty($file_name)) return false; if(!is_numeric($id)) return false; - $filename = MJTC_majesticsupportphplib::MJTC_str_replace(' ', '_',$file_name); - $filename = MJTC_majesticsupportphplib::MJTC_clean_file_path($filename); - $query = "SELECT attachmentdir FROM `".majesticsupport::$_db->prefix."mjtc_support_tickets` WHERE id = ".esc_sql($id); - $foldername = majesticsupport::$_db->get_var($query); + $download = false; + if(!MJTC_includer::MJTC_getObjectClass('user')->MJTC_isguest()){ + if(current_user_can('manage_options') || current_user_can('ms_support_ticket_tickets') ){ + $download = true; + }else{ + if( in_array('agent',majesticsupport::$_active_addons) && MJTC_includer::MJTC_getModel('agent')->isUserStaff()){ + $download = true; + }else{ + if(MJTC_includer::MJTC_getModel('ticket')->validateTicketDetailForUser($id)){ + $download = true; + } + } + } + }else{ // user is visitor + $download = MJTC_includer::MJTC_getModel('ticket')->validateTicketDetailForVisitor($id); + } + if($download == true){ + $filename = MJTC_majesticsupportphplib::MJTC_str_replace(' ', '_',$file_name); + $filename = MJTC_majesticsupportphplib::MJTC_clean_file_path($filename); + $query = "SELECT attachmentdir FROM `".majesticsupport::$_db->prefix."mjtc_support_tickets` WHERE id = ".esc_sql($id); + $foldername = majesticsupport::$_db->get_var($query); - $MJTC_datadirectory = majesticsupport::$_config['data_directory']; - $maindir = wp_upload_dir(); - $path = $maindir['basedir']; - $path = $path .'/'.$MJTC_datadirectory; + $MJTC_datadirectory = majesticsupport::$_config['data_directory']; + $maindir = wp_upload_dir(); + $path = $maindir['basedir']; + $path = $path .'/'.$MJTC_datadirectory; - $path = $path . '/attachmentdata'; - $path = $path . '/ticket/' . $foldername; - $file = $path . '/'.$filename; - // remove this code after version "1.0.7" - MJTC_includer::MJTC_getModel('majesticsupport')->generateIndexFile($path); - // remove above code after version "1.0.7" + $path = $path . '/attachmentdata'; + $path = $path . '/ticket/' . $foldername; + $file = $path . '/'.$filename; + // remove this code after version "1.0.7" + MJTC_includer::MJTC_getModel('majesticsupport')->generateIndexFile($path); + // remove above code after version "1.0.7" - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename=' . MJTC_majesticsupportphplib::MJTC_basename($file)); - header('Content-Transfer-Encoding: binary'); - header('Expires: 0'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Pragma: public'); - header('Content-Length: ' . filesize($file)); - flush(); - readfile($file); - exit(); - exit; + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename=' . MJTC_majesticsupportphplib::MJTC_basename($file)); + header('Content-Transfer-Encoding: binary'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + header('Content-Length: ' . filesize($file)); + flush(); + readfile($file); + exit(); + }else{ + include( get_query_template( '404' ) ); + exit; + }
Exploit Outline
The exploit requires retrieving a valid security nonce and targeting specific controller actions. 1. Locate a page rendering the [majesticsupport] shortcode (default: /majestic-support-controlpanel/). 2. Extract the 'MJTC_nonce' from the page source. This nonce is created for all users, including unauthenticated guests, to support the plugin's guest ticket feature. 3. Send a GET or POST request to the site with the following parameters: 'mjsmod=attachment', 'mjslay=getDownloadAttachmentByName', 'majesticsupportid=[target_ticket_id]', 'filename=[target_filename]', and 'MJTC_nonce=[extracted_nonce]'. 4. Because the vulnerable code only checks for the presence of a valid nonce and numeric IDs but fails to verify if the requester has permission to view the ticket or attachment, the plugin will serve the file content via readfile().
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.