Failles et vulnérabilités de WordPress

4 nouvelles vulnérabilités dans W3 Total Cache 0.9.4.1

Blog Failles et vulnérabilités de WordPress 4 nouvelles vulnérabilités dans W3 Total Cache 0.9.4.1
0 commentaire

Vendredi 23 septembre 2016 nous avions parlé d’une faille XSS à haut risque dans W3TC, et comme je l’avais dit à la fin de l’article “des consultants en sécurité iront fouiller afin d’en trouver d’autres“, bon, je l’ai fait.

Je l’ai fait car nous, chez WP Media, pensons que c’est important que tout le monde ai un site web sécurisé, peu importe le plugin qu’ils utilisent. Chaque mois nous faisons un audit sur des plugins gratuits du dépôt de WordPress juste pour tester, juste pour s’assurer que tout le monde est sécurisé au mieux.

4 nouvelles vulnérabilités

Il existe différentes façons de trouver des vulnérabilités dans un plugin, parfois on tombe dessus, parfois on chercher des mauvais pattern ou de mauvais echo.

Pour moi le but était de trouver quelque chose de vraiment néfaste, donc je me suis concentré sur les fichiers des utilisateurs et le code PHP.

Vous trouverez les 4 rapports sur wpvulndb :

https://wpvulndb.com/vulnerabilities/8626
https://wpvulndb.com/vulnerabilities/8627
https://wpvulndb.com/vulnerabilities/8628
https://wpvulndb.com/vulnerabilities/8629

Security Token ByPass

Le fichier /pub/apc.php est utilisé pour purger l’OPCache/APC. Le script semble être protégé par un nonce (jeton de sécurité) :

$nonce = W3_Request::get_string('nonce');
$uri = $_SERVER['REQUEST_URI'];

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

Mais la faille se situe dans l’opérateur == qui ne devrait pas être utilisé pour comparer des hashs à cause du php type juggling.

Vous trouverez un exemple de type juggling sur 3v4l.org.

Pour exploiter la vulnérabilité, le jeton doit commencer par 0e et tous les autres caractères doivent être des chiffres, alors le fameux type juggling fera ton travail. Puis l’utilisateur devra juste ajouter un paramètre dans l’URL ?nonce=0.

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

Comment obtenir un nonce qui ressemble à 0e12345678? Vous ne pouvez pas, il faut juste être ultra chanceux.

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

File Upload

En lisant le nom de la vulnérabilité, c’est déjà assez nocif pour moi. Oui, vous pouvez uploader des fichiers grâce au formulaire de support de W3TC.

Le même formulaire de support qui a provoqué la dernière faille XSS, regardez cette capture :

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

Vous pouvez ajouter des fichiers de votre ordinateur dans votre ticket de support

Quand vous créez un ticket de support vous pouvez y ajouter un ou plusieurs fichiers depuis votre ordinateur ou d’ailleurs.

Puis ces fichiers seront envoyés à l’auteur afin de l’aider à régler votre problème, dans l’idée c’est parfait.

Voici ce qu’on voit dans le code de W3TC :

        /**
* 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) {
@unlink($attachment);
}
Lines 508 to 514 from the same file

Ok, donc, quand vous envoyez le formulaire en tant qu’administrateur, W3TC va uploader nos fichiers dans son dossier temporaire /wp-content/cache/tmp/ puis les supprimera ensuite, le fichier ne vit donc que quelques millisecondes.

Et si j’envoi 2 fichiers, le premier de 2Ko contenant une backdoor et le second de 20Mo. Le temps d’envoie augmentera, le premier fichier ne sera pas encore supprimé, je pourrais donc y accéder !

Un administrateur n’est pas sencé pouvoir exécuter du code PHP maison, il n’est pas le webmaster mais juste un administrateur WordPress, ceci représente donc une vulnérabilité.

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

File Download

Même frissons pour moi, juste en lisant le nom de la faille. Dans le même écran, même formulaire vous pouvez choisir d’envoyer des fichiers de template de votre thème :

All the templates from my theme

Tous les templates de mon thème

Maintenant, vous en sélectionnez un, vous envoyez le formulaire et comme pour les fichiers précédents, vous l’envoyez à l’auteur pour l’aider à résoudre votre problème.

Comment ça marche :

        /**
* 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);
else
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));
else
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

Premièrement nos choix de templates sont ajoutés dans un tableau $attachments, deuxièmement une option est ajoutée, elle sera utilisée pour s’assurer que le fichier provient bien de ce formulaire de support, puis ces options seront supprimées une fois l’envoi terminé..

Entre la création et la suppression de ces options, le fichier files.php est appelé pour aller chercher les attachements, les vérifie avec un nonce et l’option créée

La vulnérabilité réside dans le fait que nous puissions modifier – en utilisant FireBug par exemple – le nom des templates de cette liste de choix en tout autre fichier, comme wp-config.php:

Cheat with the select and add wp-config.php

Trichons avec la balise select et ajoutons wp-config.php

Donc maintenant, une option sera créée avec ce faux fichier de template, ce qui va permettre de le valider. En utilisant le même type juggling que précédemment, je peux valider mon jeton à cause du ==.

Vous ajoutez de nouveau votre fichier de 20Mo pour pouvoir exploiter la faille.

Pointez maintenant sur le fichier files.php afin de pouvoir aller télécharger votre fichier wp-config.php, car pour les mêmes raisons que précédemment, un administrateur n’est pas sencé pouvoir lire le contenu de ce fichier, il n’est pas le webmaster mais juste un admin WordPress, ceci représente donc une vulnérabilité.

Exemple d’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

Le pire pour vous est d’autoriser un utilisateur, même un administrateur, à exécuter n’importe quel code PHP.

En utilisant la faille Upload, c’est la même chose, mais à cause du type juggling, ce n’est pas possible d’exploiter facilement.

Celle-ci est vraiment simple à utiliser, il ne s’agit que du module d’import de la configuration :

The import feature

La fonctionnalité d’import

Que va faire W3TC une fois votre fichier uploadé ? Regardons :

    /**
* 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

La mauvaise ligne est $config = eval($data); car cela signifie que tout le contenu de mon fichier sera évalué comme tout code PHP. Simplement, il nous suffit d’envoyer un script qui crée une backdoor.

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

W3TC 0.9.5

Nous avons contacté Frederick Townes pour lui parler de ces vulnérabilités, il a répondu rapidement et m’a demandé de vérifier la version 0.9.5 en zip avant de l’envoyer sur le dépôt de WordPress officiel.

Donc pour le moment il a sorti une nouvelle version du plugin sur le dépôt de WordPress, je vous recommande de vous mettre à jour au plus vite, mais d’abord vérifiez dans le support que votre site ne plante pas après !

0 commentaire