PHP Malware Finder : gestion des listes blanches

"Lime

Rappelez-vous : dans le billet précédent, nous avons découvert PHP Malware Finder. Aujourd'hui, allons plus loin et passons à la gestion des listes blanches ! Pour cela, prenons l'exemple d'un blog fonctionnant sous Wordpress. Cette gestion des listes blanches se fera en trois étapes :

  • tout d'abord, il s'agit de faire un état de l'existant, en exécutant PHP Malware Finder et en observant des faux-positifs ;
  • ensuite, la deuxième étape sera de comprendre le fonctionnement des règles et des listes blanches ;
  • enfin, la troisième étape consistera à générer la liste blanche et à l'intégrer dans les règles existantes.

Et pour finir, en bonus, un script de génération de liste blanche sera abordé. Au moment de l'écriture de cet article, la dernière version de Wordpress est la 4.7.3. La dernière version de PHP Malware Finder est la 0.3.4.

Exécution de PHP Malware Finder sur un site de test

Nous allons donc commencer par récupérer une archive de Wordpress directement sur le site officiel, afin de s'assurer qu'elle est saine :

nils@Dalaran:~/tmp$ wget https://wordpress.org/wordpress-4.7.3.tar.gz
--2017-04-11 21:54:31--  https://wordpress.org/wordpress-4.7.3.tar.gz
Résolution de wordpress.org… 66.155.40.250, 66.155.40.249
Connexion à wordpress.org|66.155.40.250|:443… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 8008833 (7,6M) [application/octet-stream]
Sauvegarde en : « wordpress-4.7.3.tar.gz »

wordpress-4.7.3.tar.gz                                      100%[=========================================================================================================================================>]   7,64M  3,27MB/s    ds 2,3s    

2017-04-11 21:54:34 (3,27 MB/s)  « wordpress-4.7.3.tar.gz » sauvegardé [8008833/8008833]

nils@Dalaran:~/tmp$ tar -xzf wordpress-4.7.3.tar.gz

Puis, décompressons-la et scannons son contenu :

nils@Dalaran:~/tmp$ cd wordpress
nils@Dalaran:~/tmp/wordpress$ phpmalwarefinder .
ObfuscatedPhp ./wp-admin/includes/class-ftp.php
DodgyStrings ./wp-admin/includes/ajax-actions.php
ObfuscatedPhp ./wp-admin/includes/class-wp-plugins-list-table.php
DodgyPhp ./wp-admin/includes/schema.php
ObfuscatedPhp ./wp-admin/includes/media.php
DodgyStrings ./wp-admin/includes/template.php
ObfuscatedPhp ./wp-admin/includes/template.php
DodgyStrings ./wp-admin/includes/upgrade.php
ObfuscatedPhp ./wp-includes/bookmark-template.php
DodgyPhp ./wp-includes/class-pop3.php
DodgyStrings ./wp-includes/class-phpmailer.php
DodgyPhp ./wp-includes/class-phpmailer.php
ObfuscatedPhp ./wp-includes/class-wp-meta-query.php
ObfuscatedPhp ./wp-includes/class-wp-tax-query.php
DodgyStrings ./wp-includes/class-wp-query.php
DodgyStrings ./wp-includes/comment.php
ObfuscatedPhp ./wp-includes/date.php
DodgyStrings ./wp-includes/deprecated.php
ObfuscatedPhp ./wp-includes/deprecated.php
DodgyStrings ./wp-includes/functions.php
DodgyPhp ./wp-includes/functions.php
DangerousPhp ./wp-includes/functions.php
DodgyStrings ./wp-includes/formatting.php
ObfuscatedPhp ./wp-includes/IXR/class-IXR-date.php
DodgyPhp ./wp-includes/load.php
DodgyStrings ./wp-includes/media.php
ObfuscatedPhp ./wp-includes/post-template.php
ObfuscatedPhp ./wp-includes/js/tinymce/tinymce.min.js
DodgyStrings ./wp-includes/post.php
ObfuscatedPhp ./wp-includes/SimplePie/Parse/Date.php

Certains fichiers sont présentés comme malveillants, mais il n'en est rien : ce sont donc des faux-positifs. Il faut donc les mettre en liste blanche, mais avant, il convient de comprendre où sont les signatures et cette liste blanche.

Signatures et listes blanches

PHP Malware Finder est basé sur YARA, un outil qui recherche des fichiers selon certains critères, comme la présence d'une chaîne de caractères, ou une expression rationnelle. Les signatures sont définies dans les fichiers asp.yar, common.yar et php.yar. On comprend alors qu'un fichier est dédié aux fichiers ASP, un autre aux fichiers PHP, et le troisième regroupe des signatures communes aux deux langages.

Passons ensuite à la lecture des fichiers asp.yar et php.yar : on voit assez vite que pour qu'un fichier soit reconnu comme malveillant, il doit non seulement remplir certaines conditions (les règles définies), mais il doit aussi ne pas remplir les conditions des fichiers de liste blanche.

En fait, les fichiers de liste blanche sontdes sommes de contrôle SHA1 de la taille des fichiers considérés comme faux-positifs. Allons maintenant à la création du fichier contenant ces informations !

Création du fichier de liste blanche

Pour ajouter nos faux-positifs en liste blanche, nous allons avoir besoin de deux choses :

  • d'abord, python-yara, une bibliothèque qui permet d'accéder à yara depuis Python ;
  • ensuite un script, generate_whitelist.py, qui se trouve être écrit... en Python.

Ce script est disponible dans le répertoire utils de PHP Malware Finder, ou bien dans \${PREFIX}/share/php-malware-finder/utils/ s'il est installé depuis pkgsrc (\${PREFIX} dépendant de l'installation de pkgsrc).

Testons donc ce script sur notre répertoire wordpress :

nils@Dalaran:~/tmp/php-malware-finder/php-malware-finder/utils$ /opt/pkg/bin/python2.7 ./generate_whitelist.py ma_liste_blanche ~/tmp/wordpress

Le résultat est alors ressemblant à celui-ci :

import "hash"

private rule maListeblanche
{
    condition:
        /* maListeblanche */
        hash.sha1(0, filesize) == "12a18329072bed94b6f9c4d9f16d7a079ca64655" or // /Users/nils/tmp/wordpress/wp-admin/includes/ajax-actions.php
        hash.sha1(0, filesize) == "6bccf04c8b46c8d6cdf79db8b509f4b76689f3bf" or // /Users/nils/tmp/wordpress/wp-admin/includes/class-ftp.php
        hash.sha1(0, filesize) == "aa6a12a0325056b9649f58f8072fa02a1e264551" or // /Users/nils/tmp/wordpress/wp-admin/includes/class-wp-plugins-list-table.php
        hash.sha1(0, filesize) == "3e73204644f0ce7b0971aad885fdcbcabba629fc" or // /Users/nils/tmp/wordpress/wp-admin/includes/media.php
        hash.sha1(0, filesize) == "81b1ae432ba765a43c6d81fb6d6c35ce72efd0e8" or // /Users/nils/tmp/wordpress/wp-admin/includes/schema.php
        hash.sha1(0, filesize) == "2ef50e790fdd42daa8ccd64d4c7c4be75d21742d" or // /Users/nils/tmp/wordpress/wp-admin/includes/template.php
        hash.sha1(0, filesize) == "9835d10a7561deeef1f8381da065b4b45d7f2662" or // /Users/nils/tmp/wordpress/wp-admin/includes/upgrade.php
        hash.sha1(0, filesize) == "b92aefa2917fc319ca7ceab092e183cafc651a6d" or // /Users/nils/tmp/wordpress/wp-includes/bookmark-template.php
        hash.sha1(0, filesize) == "cb0c5a355409d807202bbf52749a3e74a9967a6a" or // /Users/nils/tmp/wordpress/wp-includes/class-phpmailer.php
        hash.sha1(0, filesize) == "e4f0694bc96f99d5e30201171a3e7fc86e9e5ae4" or // /Users/nils/tmp/wordpress/wp-includes/class-pop3.php
        hash.sha1(0, filesize) == "c06a15f4869c5459a782b714572eacea5c82d570" or // /Users/nils/tmp/wordpress/wp-includes/class-wp-meta-query.php
        hash.sha1(0, filesize) == "72dbc1d4f2bbc8efdcdd834ecaf3771cbf17f64e" or // /Users/nils/tmp/wordpress/wp-includes/class-wp-query.php
        hash.sha1(0, filesize) == "348c3a60d99768041be690b65b008628f53badb7" or // /Users/nils/tmp/wordpress/wp-includes/class-wp-tax-query.php
        hash.sha1(0, filesize) == "0aab95245b9668f954151f4312b678fb0ee798cf" or // /Users/nils/tmp/wordpress/wp-includes/comment.php
        hash.sha1(0, filesize) == "c8c9182aa25fb92ca91fcc96c3419847acdcf6e0" or // /Users/nils/tmp/wordpress/wp-includes/date.php
        hash.sha1(0, filesize) == "5877695771fbe7a5667f4a06f4d897a37ef3fceb" or // /Users/nils/tmp/wordpress/wp-includes/deprecated.php
        hash.sha1(0, filesize) == "806d2872676ea22e0a6fa6b32fbd4652298023ee" or // /Users/nils/tmp/wordpress/wp-includes/formatting.php
        hash.sha1(0, filesize) == "3083b9a58e76d42455935811a457f29f57620145" or // /Users/nils/tmp/wordpress/wp-includes/functions.php
        hash.sha1(0, filesize) == "f53f80c4ee7446f0b605443b6d2f05acd8064d13" or // /Users/nils/tmp/wordpress/wp-includes/load.php
        hash.sha1(0, filesize) == "bea5ea598f537e7acb20b77a1421f819c0a9ec75" or // /Users/nils/tmp/wordpress/wp-includes/media.php
        hash.sha1(0, filesize) == "abcf1a0801694db4774cd2abb29b5392e10dd632" or // /Users/nils/tmp/wordpress/wp-includes/post-template.php
        hash.sha1(0, filesize) == "5ddc1e5c5c6302211b1aecbf930f76417b65d678" or // /Users/nils/tmp/wordpress/wp-includes/post.php
        hash.sha1(0, filesize) == "040ef40d245242723de200e494a27545ea0b121b" or // /Users/nils/tmp/wordpress/wp-includes/IXR/class-IXR-date.php
        hash.sha1(0, filesize) == "086986cdf03ede58494034661d38c4842af38fe3"    // /Users/nils/tmp/wordpress/wp-includes/SimplePie/Parse/Date.php
}

Il faut ensuite ajouter la règle générée à l'instant aux listes blanches déjà présentes. Pour aller vite, on peut directement éditer le fichier whitelist.yar et ajouter notre règle juste avant la dernière (IsWhitelisted). Il ne faut donc pas oublier d'ajouter dans cette dernière règle celle qu'on vient de créer. Dans mon cas, la dernière règle ressemble à cela :

private rule IsWhitelisted
{
    condition:
        Symfony or
        Wordpress or
        Prestashop or
        Magento or
        Magento2 or
        Drupal or
        Roundcube or
        Concrete5 or
        Dotclear or
        Owncloud or
        Phpmyadmin or
        Misc or
        maListeblanche
}

Vérifions maintenant que la liste blanche est bien à jour et assurons-nous qu'il n'y a plus de faux-positif dans notre répertoire :

nils@Dalaran:~/tmp/wordpress$ phpmalwarefinder ./
ObfuscatedPhp .//wp-includes/js/tinymce/tinymce.min.js

Et là, c'est le drame. Mais pourquoi ? En fait, c'est parce que le script utilisé à l'instant ne prend en compte que les fichiers PHP. Cela peut être une idée d'amélioration pour une version future.

Création facile de liste blanche pour divers logiciels PHP

Il existe un autre script fort utile : mass_whitelist.py. Son but est de faciliter la création de liste blanche pour des applications PHP connues, cela va de Wordpress à Drupal en passant par PHPMyAdmin. Il suffit de lui donner en argument le nom de l'application, l'URL de téléchargement (en remplaçant le numéro de version avec version), ainsi que les numéros de version mineurs et majeurs à rechercher.

Ce script va alors rechercher toutes les versions de l'application, les télécharger, et afficher une liste blanche les prenant toutes en compte. Par exemple, pour Wordpress :

nils@Dalaran:~/tmp/php-malware-finder/php-malware-finder/utils$ /opt/pkg/bin/python2.7 mass_whitelist.py wordpress https://wordpress.org/wordpress-__version__.tar.gz 4 7 3 | tee -a wordpress.yar

Le fichier de résultat se nomme donc wordpress.yar. Il suffira alors de le copier dans le répertoire de règles (et écraser le précédent) afin de le prendre en compte. Attention, car ce script est long, très long !

Vous avez aimé cet article ? Alors partagez-le sur les réseaux sociaux ! Si en plus vous avez des remarques, ou des propositions d'améliorations, n'hésitez pas : les commentaires sont là pour ça !

Crédit Photo : List_84 - Lime & List