wp-time-capsule < 1.17.0 Unrestricted File Upload vulnerability

Yesterday, one of my customers had their WordPress website hacked. An out-of-date plugin had allowed uploading an arbitrary PHP file, and someone had used this to drop a few files on serveral locations on the website. Luckily the IDS picked up on this quickly, and we could remove the infection and fix the hole.

What happened?

If we just restore the website, and do not plug the hole, the website will be hacked again in no time. So how did they gain access?

According to the webserver logs, a POST was performed to /wp-content/plugins/wp-time-capsule/wp-tcapsule-bridge/upload/php/index.php. That index.php file is just including /wp-content/plugins/wp-time-capsule/wp-tcapsule-bridge/upload/php/UploadHandler.php and instantiating the UploadHandler class. After sending the POST request to index.php, a webshell was created on the server, which was then used to drop the other files.

There was a .htaccess file in /wp-content/plugins/wp-time-capsule/wp-tcapsule-bridge that could have prevented this, but not every webserver even supports .htaccess files.

First thing I did was compare UploadHandler.php to the most recent version of the file. Apart from a few empty lines, the difference between UploadHandler.php in 1.16.3 and 1.17.0 is:

@@ -377,10 +379,21 @@
             return false;

-        if (!in_array($file->type, $this->options['accept_file_types'])) {
+        $allowed_extensions = array('.sql', '.gz', '.crypt');
+        $found = false;
+        foreach ($allowed_extensions as $extension) {
+            if(strrpos($file->name, $extension) + strlen($extension) === strlen($file->name)){
+                $found = true;
+            }
+        }
+        if (!$found) {
             $file-&>error = $this->get_error_message('accept_file_types');
             return false;
         if ($uploaded_file && is_uploaded_file($uploaded_file)) {
             $file_size = $this->get_file_size($uploaded_file);
         } else {

The version 1.16.3 used content-type (a untrusted field) to check for file type, the new version checks the actual file extension. If you can modify the headers of the HTTP-request to spoof a application/sql type of file, you can basically upload anything you like.

Lets just make a proof of concept here. First create a file test.php with some malicious code. Then upload it using:

curl -H Expect: -F "files=@test.php;type=application/sql" http://www.example.com/wp-content/plugins/wp-time-capsule/wp-tcapsule-bridge/upload/php/index.php

Now your file is available through http://www.example.com/wp-content/plugins/wp-time-capsule/wp-tcapsule-bridge/upload/php/text.php

Version 1.17.0 of the wp-time-capsule plugin patches the vulnerability by implementing a file extension check, but the changelog does not mention this at all. I believe making a coding error could happen, but covering it up is unpermissible. I prefer to stay away from software developers that don't report on their security problems.

Had this vulnerability been reported transparently, then the WP management software this customer uses would probably have flagged this update as necessary.


Why was wp-time-capsule out of date in the first place? Because the customer installed a plugin to defer and hide updates... They install updates through some central WordPress management platform like InfiniteWP or ManageWP.

© GeekLabInfo wp-time-capsule < 1.17.0 Unrestricted File Upload vulnerability is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)