Authenticated Arbitrary File Upload Vulnerability in Estatik
With our service we notify customers when they are using plugins with known vulnerabilities in the version in use (as well as providing them data on vulnerabilities that existed in other versions of the plugin), but the usefulness of that is somewhat limited since telling you the plugin is vulnerable without being able to update to a fixed version is not the best solution. While we can usually provide someone with a temporary fix until the developer fully fixes the issue, what we really want to do is to make sure it eventually gets fixed so that everyone has a chance to be protected, even if they are not yet using our service.
That often isn’t an easy task. Often times the developers of plugins never responds or fixes the vulnerability when we contact them about it, even in cases where we indicated that vulnerability is already being exploited. When that happens the next step is notify the people running the Plugin Directory, who will the remove the plugin from it pending a fix. At least that is what is supposed to happen, in a number of incidents we have found that plugins have returned without the vulnerability actually being fixed, an issue that at least one person involved with WordPress doesn’t want people to know about.
Another issue that comes up from time to time is that a vulnerability is fixed, but since the related code isn’t fully secured, a lesser vulnerability remains. And then we need to try deal with that, which is what has happened with the plugin Estatik.
Back in July we spotted evidence that hackers may have been targeting the plugin as of June of last year and we found an arbitrary file upload vulnerability in the plugin that would likely be something they would exploit if they knew about it. We contacted the developer about the issue and after waiting for a response or a fix for a week we contacted the Plugin Directory and the plugin was removed. Earlier this week the plugin returned and in checking over the new version, 2.3.0, we found that vulnerability was gone, but the change to fix it left an authenticated arbitrary file upload vulnerability in the plugin. What that means is arbitrary files can still be uploaded, but only by someone that is logged in to WordPress. For a lot of websites, that isn’t much of an issue since many websites only have a single account with the Administrator role, which can usually upload arbitrary files, and other websites only have few trusted users with accounts.
To fix the previous vulnerability the developer removed the following line that allowed those not logged in to access the function es_prop_media_images() through WordPress’s AJAX functionality:
add_action('wp_ajax_nopriv_es_prop_media_images', 'es_prop_media_images'); |
The plugin continues to make the function accessible via the AJAX functionality when logged in through this line:
add_action('wp_ajax_es_prop_media_images', 'es_prop_media_images'); |
Since the function is only intended to accessible by Administrator level users there needs to be a check done in the function to make sure the request is not being made by a lower level user. Nothing along that lines was added in 2.3.0.
The plugin is also susceptible to cross-site request forgery (CSRF) based arbitrary file uploading due to a lack of a nonce.
We mentioned these issues when we originally contacted the developer of the plugin, but they apparently ignored it. We have contacted them again about the issue and hopefully we can work with them to get the issue fully resolved.
Proof of Concept
The following proof of concept will upload the selected file and put it in the current month’s directory inside of the /wp-content/uploads/ director, when logged in to WordPress. The name of the file in the upload directory with be the time the file was saved as output by the function time() followed by a “_” and then name of the as it was uploaded.
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" method="POST" enctype="multipart/form-data"> <input type="hidden" name="action" value="es_prop_media_images" /> <input type="file" name="es_media_images[]" /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- 7/25/2016 – Developer notified.
- 8/19/2016 – Developer notified again.
- 8/19/2016 – Developer responds.
- 8/21/2016 – Version 2.3.1 released, which fixes issue.