700,000 WordPress Users Affected by Zero-Day Vulnerability in File Manager Plugin

on September 1, 2020, the Wordfence Threat Intelligence team was alerted to the presence of a vulnerability being actively exploited in File Manager, a WordPress plugin with over 700,000 active installations. This vulnerability allowed unauthenticated users to execute commands and upload malicious files on a target site.

A patch was released this morning on September 1, 2020. We are seeing this vulnerability being actively exploited in the wild, therefore, we urge users to update to the latest version, 6.9, immediately since it contains a patch for this vulnerability and will keep you protected.

Wordfence Premium users as well as those still using the Free version are protected against this attack campaign by the Wordfence firewall’s built-in file upload protection, though the Wordfence firewall needs to be optimized in order to protect your site from this vulnerability.

While analyzing the vulnerability, we discovered that it was possible to bypass the built-in file upload protection so we deployed an additional firewall rule for maximum coverage. Wordfence Premium customers received this new firewall rule today, September 1, 2020, at 2:56PM UTC. Free Wordfence users will receive the rule after thirty days on October 1, 2020.

Description: Remote Code Execution
Affected Plugin: File Manager
Plugin Slug: wp-file-manager
Affected Versions: 6.0-6.8
CVSS Score: 10.00 (Critical)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Patched Versions: 6.9

File Manager is a plugin designed to help WordPress administrators manage files on their sites. The plugin contains an additional library, elFinder, which is an open-source file manager designed to create a simple file management interface and provides the core functionality behind the file manager. The File Manager plugin used this library in a way that introduced a vulnerability.

The core of the issue began with the File Manager plugin renaming the extension on the elFinder library’s connector.minimal.php.dist file to .php so it could be executed directly, even though the connector file was not used by the File Manager itself. Such libraries often include example files that are not intended to be used “as-is” without adding access controls, and this file had no direct access restrictions, meaning the file could be accessed by anyone. This file could be used to initiate an elFinder command and was hooked to the elFinderConnector.class.php file.

// run elFinder
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();


Any parameters sent in a request to connector.minimal.php would be processed by the run() function in the elFinderConnector.class.php file, including the command that was supplied in the cmd parameter.

public function run()
{
$isPost = $this->reqMethod === 'POST';
$src = $isPost ? array_merge($_GET, $_POST) : $_GET;
$maxInputVars = (!$src || isset($src['targets'])) ? ini_get('max_input_vars') : null;
if ((!$src || $maxInputVars) && $rawPostData = file_get_contents('php://input')) {
// for max_input_vars and supports IE XDomainRequest()
$parts = explode('&', $rawPostData);
if (!$src || $maxInputVars < count($parts)) {
$src = array();
foreach ($parts as $part) {
list($key, $value) = array_pad(explode('=', $part), 2, '');
$key = rawurldecode($key);
if (preg_match('/^(.+?)[([^[]]*)]$/', $key, $m)) {
$key = $m[1];
$idx = $m[2];
if (!isset($src[$key])) {
$src[$key] = array();
}
if ($idx) {
$src[$key][$idx] = rawurldecode($value);
} else {
$src[$key][] = rawurldecode($value);
}
} else {
$src[$key] = rawurldecode($value);
}
}
$_POST = $this->input_filter($src);
$_REQUEST = $this->input_filter(array_merge_recursive($src, $_REQUEST));
}
}</pre>
<code></code> if (isset($src['targets']) && $this->elFinder->maxTargets && count($src['targets']) > $this->elFinder->maxTargets) { $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_MAX_TARGTES))); } $cmd = isset($src['cmd']) ? $src['cmd'] : '';

The list of commands available in elFinder are as follows.

/**
* Commands and required arguments list
*
* @var array
**/
protected $commands = array(
'abort' => array('id' => true),
'archive' => array('targets' => true, 'type' => true, 'mimes' => false, 'name' => false),
'callback' => array('node' => true, 'json' => false, 'bind' => false, 'done' => false),
'chmod' => array('targets' => true, 'mode' => true),
'dim' => array('target' => true, 'substitute' => false),
'duplicate' => array('targets' => true, 'suffix' => false),
'editor' => array('name' => true, 'method' => true, 'args' => false),
'extract' => array('target' => true, 'mimes' => false, 'makedir' => false),
'file' => array('target' => true, 'download' => false, 'cpath' => false, 'onetime' => false),
'get' => array('target' => true, 'conv' => false),
'info' => array('targets' => true, 'compare' => false),
'ls' => array('target' => true, 'mimes' => false, 'intersect' => false),
'mkdir' => array('target' => true, 'name' => false, 'dirs' => false),
'mkfile' => array('target' => true, 'name' => true, 'mimes' => false),
'netmount' => array('protocol' => true, 'host' => true, 'path' => false, 'port' => false, 'user' => false, 'pass' => false, 'alias' => false, 'options' => false),
'open' => array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false, 'compare' => false),
'parents' => array('target' => true, 'until' => false),
'paste' => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false, 'renames' => false, 'hashes' => false, 'suffix' => false),
'put' => array('target' => true, 'content' => '', 'mimes' => false, 'encoding' => false),
'rename' => array('target' => true, 'name' => true, 'mimes' => false, 'targets' => false, 'q' => false),
'resize' => array('target' => true, 'width' => false, 'height' => false, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false, 'quality' => false, 'bg' => false),
'rm' => array('targets' => true),
'search' => array('q' => true, 'mimes' => false, 'target' => false, 'type' => false),
'size' => array('targets' => true),
'subdirs' => array('targets' => true),
'tmb' => array('targets' => true),
'tree' => array('target' => true),
'upload' => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false, 'upload' => false, 'name' => false, 'upload_path' => false, 'chunk' => false, 'cid' => false, 'node' => false, 'renames' => false, 'hashes' => false, 'suffix' => false, 'mtime' => false, 'overwrite' => false, 'contentSaveId' => false),
'url' => array('target' => true, 'options' => false),
'zipdl' => array('targets' => true, 'download' => false)
);

The good news is that elFinder has built-in protection against directory traversal, so an attacker would be unable to use any of these commands on any files outside of the plugins/wp-file-manager/lib/files/ directory.

The attacks we are seeing in the wild are using the upload command to upload PHP files containing webshells hidden in an image to the wp-content/plugins/wp-file-manager/lib/files/ directory.

Fortunately, both Wordfence Premium and free users have been protected against the campaign targeting this vulnerability. However, for optimal protection we created an additional firewall rule.

Why We Created An Additional Firewall Rule

While our firewall’s built-in protection prevented direct file upload, we determined that it was possible to send a specially crafted request that would create an empty PHP file by using the mkfile command in the cmd parameter. An attacker could then send a separate request to save malicious code to that file by sending a request with the cmd parameter set to put. Additionally, other bypasses may be possible, so we created a firewall rule to completely block any and all access to the connector.minimal.php file.

The File Manager plugin patched the issue by removing the lib/php/connector.minimal.php file from the plugin altogether, and manually removing this file should also prevent attackers from exploiting this vulnerability without impacting normal functionality. This bypass has not been targeted in the wild.

A Small Note From The Team at Wordfence

When using utility plugins like this file manager plugin, we recommend taking the utmost precaution. Plugins like this one contain several features that if exposed within the admin area of your WordPress installation, could cause serious problems.

A file manager plugin like this would make it possible for an attacker to manipulate or upload any files of their choosing directly from the WordPress dashboard, potentially allowing them to escalate privileges once in the site’s admin area. For example, an attacker could gain access to the admin area of the site using a compromised password, then access this plugin and upload a webshell to do further enumeration of the server and potentially escalate their attack using another exploit.

For this reason, we recommend uninstalling utility plugins, like file management plugins, when they are not in use, so that they do not create an easy intrusion vector for attackers to escalate their privileges.

Indicators of Compromise

The Wordfence firewall has blocked over 450,000 exploit attempts targeting this vulnerability over the past several days. We are seeing attackers attempting to inject random files, all of which appear to begin with the word “hard” or “x.” From our firewall attack data, it appears that attackers may be probing for the vulnerability with empty files and if successful, may attempt to inject a malicious file.

Here is a list of some of the files we are seeing uploaded:

  • hardfork.php
  • hardfind.php
  • x.php

Please look for these files in the /wp-content/plugins/wp-file-manager/lib/files directory of your site.

The top 6 attacking IP addresses that we are seeing are as follows.

  • 185.222.57.183
  • 185.81.157.132
  • 185.81.157.112
  • 185.222.57.93
  • 185.81.157.177
  • 185.81.157.133

Please look for these offending IP Addresses in your site’s log files.

Source Credit – 700,000 WordPress Users Affected by Zero-Day Vulnerability in File Manager Plugin

Wordpress Experts
Elevating Your WordPress Experience Beyond Limits.