Certains d’entre vous l’ont peut-être constaté, il était plutôt compliqué d’accéder à unicoda.com durant les dernières 48h. En effet, il se trouve que le site a été la cible d’une attaque de type brute force qui l’a mis à mal. Résultat, un processus apache qui décolle et accapare toutes les ressources de la machine jusqu’au déni de service. Retour sur la folle vie d’un serveur attaqué.
Tout commence le 25 août 2016 aux alentours de 19h, la première requête de la série apparaît à 18 heures 46 minutes et 25 secondes pour être précis.
191.96.249.54 - - [25/Aug/2016:18:46:25 +0200] "POST /xmlrpc.php HTTP/1.0" 200 579 "-" "Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)" 191.96.249.54 - - [25/Aug/2016:18:46:25 +0200] "POST /xmlrpc.php HTTP/1.0" 200 579 "-" "Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)" 191.96.249.54 - - [25/Aug/2016:18:46:25 +0200] "POST /xmlrpc.php HTTP/1.0" 200 579 "-" "Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)"
À cette heure-là, pas de problème, le serveur fonctionne correctement. La première alerte sera levée par le système de monitoring d’OVH à 22h54 ce même jour. Le serveur a déclaré forfait et ne répond plus au ping. Quelques minutes plus tard, le support intervient et redémarre le serveur. Une nouvelle alerte sera levée vers 4h du matin, avec intervention du support. En découvrant les mails le matin, je ne flaire pas immédiatement l’attaque. Le support est intervenu, il n’y a pas de précision indiquant si le problème vient du logiciel ou du matériel côté hébergeur, le site ne s’affichant pas, j’effectue à mon tour un redémarrage du serveur et m’assure que les différents services sont bien repartis. Tout semble fonctionner… Pourtant, même scénario dans la nuit de vendredi à samedi avec deux interventions du support. Quelque chose cloche, je continue de vaquer à mes occupations lorsque le serveur devient une nouvelle fois inaccessible samedi vers midi. Pas doute il y a un problème, je vais devoir effectuer des vérifications dès que possible.
En fin d’après-midi le samedi 27, je me connecte donc au serveur après l’avoir redémarré. Pas d’étrangeté du côté des processus, si ce n’est plusieurs process apache qui tournent en épuisant la majeure partie des ressources. « Houston, nous avons un problème. » Une telle utilisation des processus apache suggère un trafic important du côté site web. Direction les logs et là bingo, une même IP effectue des requêtes POST sur /xmlrpc.php en boucle et mets le serveur à genou. Ni une ni deux, je décide de prendre les mesures qui s’imposent :
iptables -A INPUT -s 191.96.249.54 -j DROP
Le changement est flagrant, les indicateurs repassent au vert, le serveur respire. Le problème immédiat est réglé. Il faut maintenant s’assurer que cela ne se reproduise plus et qu’une machine tentant une telle attaque soit automatique bloquée. Ça tombe bien, Fail2ban va pouvoir s’en charger !
Nous allons donc ajouter la configuration suivante à Fail2ban (fichier jail.conf :
[wordpress-xmlrpc] enabled = true port = https,http filter = wordpress-xmlrpc logpath = /var/log/apache2/wordpress_access.log bantime = 86400 maxretry = 1
Au niveau du paramètre, 86400 secondes de bannissement (24h) et une tolérance limite de une tentative de connexion au fichier sur 600 secondes (par défaut). On ajoute ensuite le filtre par création du fichier wordpress-xmlrpc.conf dans le dossier filter.d :
[INCLUDES] before = common.conf [Definition] failregex = <HOST> - .*(GET|POST) .*/xmlrpc.php ignoreregex =
Il ne faut pas oublier de s’assurer que Fail2ban a accès au fichier de log en lecture, en théorie pas de problème. La regex doit également être modifiée pour coller à la structure des logs. Afin de tester la configuration, on peut utiliser la commande suivante, en étant particulièrement attentif aux lignes commençant par ERROR :
sudo fail2ban-client -d
Il est également possible de tester votre regex en créant un fichier contenant la ligne que nous souhaitons vérifier et en demandant à fail2ban de vérifier la regex sur le contenu du fichier :
fail2ban-regex /chemin/vers/test.log "<HOST> - .*(GET|POST) .*/xmlrpc.php"
La regex correspond à la chaîne de caractère entre double quote. Par ailleurs, si ce n’est pas fait et si on a la chance de disposer d’une IP fixe pour votre modem personnel, on peut en profiter pour mettre celle-ci en liste blanche dans le fichier de configuration jail.conf :
[DEFAULT] # "ignoreip" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1/8 xxx.xxx.xxx.xxx
Pour vérifier que la règle est active, on pourra utiliser la commande :
sudo fail2ban-client status
Voilà une configuration qui devrait limiter les dégâts lors des prochaines tentatives d’attaque. Le comble de cette histoire, c’est que j’avais pris connaissance plus tôt cette année des risques liés à xmlrpc.php dans WordPress, mais je n’avais pas pris le temps de mettre en place les protections nécessaires. C’est désormais chose faite.
Cette première attaque avec un impact visible sur les services hébergés m’a donc permis d’approfondir mes connaissances de fail2ban. Je retiendrai bien évidemment le diagnostic un peu tardif mais néanmoins rapide du problème. Je pense qu’il y a des choses à creuser de ce côté-là pour tenter d’avoir une remontée automatique d’informations dès que le serveur détecte un éventuel problème.
Chronologie
25-08-2016 22:50:07 Destination Host Unreachable 25-08-2016 23:40:57 Reboot HARD 26-08-2016 04:19:05 Destination Host Unreachable 26-08-2016 04:31:13 Reboot HARD 26-08-2016 22:37:06 Destination Host Unreachable 26-08-2016 23:29:00 Reboot HARD 27-08-2016 02:43:06 Destination Host Unreachable 27-08-2016 03:06:59 Reboot HARD 27-08-2016 12:39:06 Destination Host Unreachable 27-08-2016 12:46:08 Reboot HARD
Au passage, je tiens à remercier le support technique pour leur intervention à chaque fois que le serveur devenait indisponible (Jonathan L. et Nicolas D.).
Quelques chiffres
IP source : 191.96.249.54
84 524 requêtes
À chaque installation de WordPress que je suis amené à faire ou à modifier, je rajoute dorénavant systématiquement la ligne suivante dans le fichier .htaccess :
RewriteRule ^xmlrpc\.php$ « http\:\/\/0\.0\.0\.0\/ » [R=301,L]
Une vraie plaie ces attaques XML-RPC pingback..