WordPress Flaws and Vulnerabilities

4 New Security Flaws in W3 Total Cache

Blog WordPress Flaws and Vulnerabilities 4 New Security Flaws in W3 Total Cache

On friday, 23th September 2016 we talked about a High Risk XSS vulnerability in W3TC, and like I said at the end of this post “security consultant will try to find more“, well, I did.

I did it because we, at WP Media,  think it’s important for everyone to have a secure website, whatever the plugin they’re using. Every month we do some security audit on a few plugins from the free WordPress repository just to test, just to be sure that everyone is safe.

4 New Vulnerabilities

There is many different ways to find vulnerabilities in a plugin, sometimes you fall on them, sometimes you look for some bad patterns or echoing stuff.

For me, the goal was to find something very harmful so I focused on user’s file and PHP code.

You can find the 4 reports on wpvulndb:


Security Token ByPass

The /pub/apc.php file is useful to empty the OPCache/APC. The script seems protected by a nonce (aka security token):

$nonce = W3_Request::get_string('nonce');

if (wp_hash($uri) == $nonce) {
3 lines from /pub/apc.php

But the flaw stays in the == operator which is not the one to use when you want to compare hashes because of PHP type juggling.

You can find an example of type juggling on 3v4l.org.

To exploit the vulnerability, the token has to start with 0e and all other chars have to be numbers, then the user can just add a parameter in the url like ?nonce=0 and it will be validated.

Example of URL: http://example.com/wp-content/plugins/w3-total-cache/pub/apc.php?nonce=0&command=reload_files

How to get a nonce like 0e12345678? You can’t guess, just be extra lucky.

DREAD Score: 0+1+8+0+8 = Low Risk

File Upload

Reading the vulnerability name is already harmful for me. Yes, you can upload files in W3TC support form.

The same support form with the XSS vulnerability, check this screenshot:

You can add custom files to be sent with your support ticket

You can add custom files to be sent with your support ticket

When you’re creating a support ticket, you can add one or more of your files from your computer, or whatever.

Then this file will be sent to the author to help him resolving your issue, good idea.

When we look at the code, W3TC does that:

* Attach other files
if (!empty($_FILES['files'])) {
$files = (array)$_FILES['files'];
for ($i = 0, $l = count($files); $i < $l; $i++) {
if (isset($files['tmp_name'][$i]) && isset($files['name'][$i]) && isset($files['error'][$i]) && $files['error'][$i] == UPLOAD_ERR_OK) {
$path = W3TC_CACHE_TMP_DIR . '/' . $files['name'][$i];
if (@move_uploaded_file($files['tmp_name'][$i], $path)) {
$attachments[] = $path;
Lines 401 to 414 from /lib/W3/AdminActions/SupportActionsAdmin.php
* Remove temporary files
foreach ($attachments as $attachment) {
if (strstr($attachment, W3TC_CACHE_TMP_DIR) !== false) {
Lines 508 to 514 from the same file

Ok, so, when you submit the form as an administrator, W3TC uploads our file in its temporary folder /wp-content/cache/tmp/ then will delete them right after that, the file will live only a few milliseconds.

But what if I try to send 2 files, the first one is a 2 Kb malicious PHP file containing a backdoor, the second one is a 20 Mb file. The submission will last more longer, the first file won’t be deleted since the second one is not uploaded, I can now access to the first file.

An administrator is not always allowed to execute custom PHP code, he’s not the webmaster but a WordPress administrator, so this represent a vulnerability.

DREAD Score: 10+8+6+2+8 = High Risk

File Download

Same chills for me, when I read this kind of flaw. In the same screen, same form you can also select files from your theme:

All the templates from my theme

All the templates from my theme

Now you select one, you send the form and same as for the files before, you will send it to the author to help him to fix the issue.

How does it work:

* Attach templates
foreach ($templates as $template) {
if (!empty($template)) {
$attachments[] = $template;
Lines 392 to 399 from same file again
        foreach ($attachments as $attachment) {
if (is_network_admin())
update_site_option('attachment_' . md5($attachment), $attachment);
update_option('attachment_' . md5($attachment), $attachment);
Lines 476 to 481
* Remove temporary files
foreach ($attachments as $attachment) {
// ...
if (is_network_admin())
delete_site_option('attachment_' . md5($attachment));
delete_option('attachment_' . md5($attachment));
Lines 508 to 519
$attachment_location = filter_var(urldecode($_REQUEST['file']), FILTER_SANITIZE_STRING);
$md5 = md5($attachment_location);
$nonce = $_REQUEST['nonce'];
$stored_nonce = get_site_option('w3tc_support_request') ? get_site_option('w3tc_support_request') : get_option('w3tc_support_request');
$stored_attachment = get_site_option('w3tc_support_request') ? get_site_option('attachment_' . $md5) : get_option('attachment_' . $md5);

if (file_exists($attachment_location) && $nonce == $stored_nonce && !empty($stored_nonce) && $stored_attachment == $attachment_location) {
Lines 28 to 34 from /pub/files.php

First, our choices are added to the attachments array, secondly an option is added, this will be used to be sure that this file was chosen from this support form, then this options are deleted when the submission is done.

Between the option creation and deletion, the files.php file is called to get the attachment, verified with a nonce and with the created option.

The vulnerability stays in the fact that we can modify – using FireBug for example – the templates name to another existing file from the site, like wp-config.php:

Cheat with the select and add wp-config.php

Cheat with the select and add wp-config.php

So now, an option has been created with this fake theme template. Then using the same type juggling flaw as before, I can validate the nonce because of the ==.

You also have to add a 20 Mb file to gain time to exploit this.

Pointing on the files.php URL you can now download the wp-config.php, because for the same reason as before, an administrator is not always allowed to read the config file, he’s not the webmaster but a WordPress administrator, so this represent a vulnerability.

Example of URL: http://example.com/wp-content/plugins/w3-total-cache/pub/files.php?file=/Users/julio/Sites/wpsolo/wp-config.php&nonce=0

DREAD Score: 10+2+4+2+6 = Low Risk

PHP Eval

The worst for you is to allow a user, even an administrator, to eval any PHP code.

Using the File Upload flaw is a lookalike one, but because of the type juggling, it’s not possible to exploit it easily.

This one is so much easy to exploit using the import settings feature:

The import feature

The import feature

What W3TC will do once your file is uploaded? Check it:

* Imports config content
* @param string $filename
* @return boolean
function import($filename) {
if (file_exists($filename) && is_readable($filename)) {
$data = file_get_contents($filename);
if (substr($data, 0, 5) == '<?php')
$data = substr($data, 5);

$config = eval($data);

if (is_array($config)) {
foreach ($config as $key => $value)
$this->set($key, $value);

return true;

return false;
The import() method from the W3_Config class

The bad line is $config = eval($data); because it means that all my file content will be evaluated like any other PHP code. Basically we can send a PHP script that will create a backdoor.

DREAD Score: 10+8+8+2+10 = High Risk

W3TC 0.9.5

We contacted Frederick Townes to tell him about these vulnerabilities, he replied very quickly asking me to test the 0.9.5 zip file before sending it on the official repository.

So for now he has patched the free plugin on the repository already, we recommend you to update as soon as possible, but first check the support tab to be sure your site won’t crash.