Maitriser son infrastructure

Récemment l'un de mes clients a subit une importante attaque sur l'un de ses sites. Ce n'est pas quelque chose d'exceptionnel, ça arrive de temps à autre et généralement ça se règle assez facilement. Mais dans le cas présent il y a eu quelques complications et c'est une bonne démonstration de la nécessité de toujours garder à l'esprit de pouvoir contrôler les différents éléments de son infrastructure.

En guest star dans ce petit article nous allons parler de Cloudflare, CrowdSec et Ezoic.

Présentation de l'existant
Description de l'attaque
Première réaction
Solution
Conclusion


Présentation de l'existant

Au moment de l'attaque le site est hébergé sur l'un de mes serveur. C'est une ancienne configuration en Debian 9 qui sera remise à niveau à la sortie de Debian 11. Nous sommes sur un grand classique avec Apache, PHP 7.3 et Mariadb. La charge serveur est faible et le nombre de visiteurs par mois raisonnable (environ 550k visiteurs / mois). Le site concerné représente environ la moitié de l'activité du serveur, c'est à dire autour de 250k visiteurs / mois.

La particularité ici c'est que le site se trouve derrière les Proxy d'Ezoic, je reviendrai sur ce point plus tard quand je parlerai de l'attaque.

Pour sécuriser tout ça j'utilise Crowdsec sur tous mes serveurs. C'est un agent dans le même genre que Fail2ban mais je le trouve bien plus souple, modulaire, facile à configurer. De plus l'équipe de dev est Française et les devs sont très disponibles et toujours à l'écoute pour leur remonter des idées. Si vous ne connaissez pas le produit n'hésitez pas à vous renseigner !

Crowdsec va se charger de parser les logs et tenter d'identifier des menaces pour ensuite bloquer les attaques au niveau du parefeu. J'ai également un script (ou bouncer dans le langage CrowdSec) qui va remonter ces IPs à Cloudflare pour les bloquer directement sur leur infra.

Mais comme je l'ai dis plus haut, ce site passe directement par les proxy d'Ezoic sur lesquels je n'ai aucun contrôle. Impossible de bloquer une IP directement sur leur infra. De plus ils ne fournissent pas de liste d'IP fiable sur laquelle se baser ou d'en-tête indiquant l'IP source du visiteur. Cela oblige à tenter de récupérer tant bien que mal les IPs visiteurs, sans que cela ne soit très fiable. Par conséquent pour éviter de bloquer les proxy je whitelist les requêtes qui ont dans leur "user agent" X-Middleton qui est une information ajoutée par les relais Ezoic. Ce n'est franchement pas une bonne idée mais vu que de toute façon je ne peux pas contrôler l'activité de ce qui passe par leurs proxy je fais avec.


Description de l'attaque

L'attaque en elle même est assez simple, on prends des tas d'IPs et on leur demande de balancer des milliers de requêtes web sur un site. Les requêtes sont faites d'une chaine de caractère aléatoire, voici un petit exemple :
18.159.39.54 - - [28/Apr/2021:19:32:43 +0200] "GET //?35269008848799742SsL67526501915823685q HTTP/2.0" 301 217 "https://www.fbi.com/floodlab.fr" "Mozilla/5.0 (X11; Linux x86_64; rv:2.2a1pre) Gecko/20100101 Firefox/4.2a1pre X-Middleton/1" floodlab.fr

18.194.168.213 - - [28/Apr/2021:19:32:43 +0200] "GET //?554673058414960561SDz9225610022246514N HTTP/2.0" 301 217 "https://r.search.yahoo.com/floodlab.fr" "Mozilla/5.0 (X11; U; FreeBSD i386; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/4.0.207.0 Safari/532.0 X-Middleton/1" floodlab.fr

Comme vous pouvez le voir l'IP est toujours différente, tout comme l'URL ainsi que le referer et l'user-agent. L'idée est intéressante. La requête est différente à chaque appel, ce qui implique qu'il est + compliqué de la bloquer. Ce qui pose un problème sur Wordpress qui à chaque appel de ce genre va aller dire bonjour à la base de données pour voir si il a quelque chose qui correspond à cette demande. Après vérification il se rend compte qu'il n'y a rien, et il est configuré pour envoyer une 301 (redirection) vers la home, ce qui peut éventuellement engendrer d'autres appels à la bdd. Même avec un NGinx en front qui aurait un cache sur les requêtes 301 ou 404 il ferait systématiquement suivre à Apache car c'est une nouvelle requête. Idem pour les CDN qui ne mettent pas en cache les 301/404 et qui de toute façon ne mettent en cache que sur des urls identiques.

Sur la soirée le serveur a reçu environ 700k requêtes de ce genre, forcément il n'apprécie pas vraiment et voici par exemple ce qu'en pense le CPU (voir le début du graph) :


Première réaction

Au début je suis informé des problèmes par un dev qui travaille sur le serveur et m'indique avoir des erreurs "Too Many Connections" sur MySQL. Je suis un peu étonné car ce serveur a une activité très stable, je me dis qu'il y a peut être un pic d'activité. Je vais vérifier les logs et je constate un gros bordel... Bon, no stress, je suis habitué à ce genre de chose, un petit scénario CrowdSec et une rule Cloudflare et on en parle plus... Seulement voilà, je constate que le site est configuré en direct sur Ezoic, qu'il utilise leurs NS et passe uniquement par leurs proxy sans passer par Cloudflare au préalable...

Ha... Là je me rends compte rapidement que mes options sont extrêmement limitées... En fait je ne peux quasiment rien faire pour protéger le site. J'explique la situation au client, j'envisage un instant qu'il passe le site sur Cloudflare, ou à minima qu'il vire les proxy Ezoic que je puisse essayer de bloquer les requêtes directement au niveau du parefeu. Mais visiblement il galère à désactiver les proxy et on reste avec les proxy Ezoic en front. De + changer les NS est une opération qui prends généralement beaucoup de temps pour que cela propage bien.

Tant bien que mal j'essaie de temporiser, avec notamment une rewrite rule dans le .htaccess. Après pas mal d'essais (je ne suis pas bon là dessus) j'arrive à sortir une rule qui balance bien une 403 (access denied) aux attaquants, mais ça bloque une partie des fonctions du site. Et de toute façon même en renvoyant une 403 (donc sans aucun appel PHP ou MySQL) la charge serveur descend difficilement sous les 90%.

Des plugins WP pour bloquer sur l'applicatif ne serviraient pas à grand chose non plus. Tout d'abord car on a du mal à récupérer l'ip réelle du visiteur (merci les proxy Ezoic) et parce que de toute façon quand une telle attaque arrive sur l'applicatif c'est déjà trop tard.

Par conséquent après pas mal de galères (il est déjà 21H, j'ai le cerveau + lent) on décide de switcher le site sur Cloudflare. Après quelques galères on arrive à le configurer et à pouvoir agir.


Solution

Au final on décide tout de même de changer les NS malgré le fait que l'on sait que cette opération prendra du temps. Mais dès que la décision est prise je commence à adapter ma configuration.

Tout d'abord j'utilise CrowdSec pour identifier les attaquants et les bloquer. Vu que les attaquants utilisent une url en **//?"chaine alphanum"** je choisis de faire le bourrin et de bloquer tout visiteur qui s'amuserait à balancer une requête en **//?**

Le grand avantage de CrowdSec est la simplicité avec laquelle on écrit un filtre (ou un scénario pour parler le CrowdSec). Dans le cas présent mon filtre sera très simple, voici comment est rédigé mon scénario :

filter: "evt.Meta.log_type == 'http_access-log' && evt.Parsed.request startsWith '//?'"

Et je configure ça en mode **Trigger** pour déclencher un ban dès qu'une IP tente une telle requête.

Pour traduire mon filtre cela veut dire que je vais lire le fichier de log déclaré dans http_access-log et que je veux sélectionner les requêtes commençant par //? Voilà, c'est tout, pas de regex compliquée, juste un "startswith" et mon bout de chaîne...

Lorsque CrowdSec détecte un visiteur qui fait une telle requête l'IP est bloquée sur le parefeu du serveur (via ipset) même si dans notre cas cela ne sert à rien. Mais j'ai également un script qui va récupérer ces IPs pour aller les bloquer directement sur CloudFlare. Et là c'est radical, en quelques dizaines de minutes l'attaque est terminée, tout revient à la normale. Ce sont encore plus de 750k requêtes qui seront ainsi bloquées directement sur Cloudflare avant même d'arriver sur le serveur.

Voici des extraits de logs de CrowdSec quand il a commencé à faire le ménage : time="28-04-2021 21:58:06" level=info msg="(srv/crowdsec) si/flood by ip 124.107.231.80 (PH) : 4h ban on Ip 124.107.231.80" time="28-04-2021 21:58:18" level=info msg="(srv/crowdsec) si/flood by ip 88.202.177.242 (NL) : 4h ban on Ip 88.202.177.242" time="28-04-2021 21:58:22" level=info msg="(srv/crowdsec) si/flood by ip 198.144.120.177 (BZ) : 4h ban on Ip 198.144.120.177" time="28-04-2021 21:58:24" level=info msg="(srv/crowdsec) si/flood by ip 98.170.57.231 (US) : 4h ban on Ip 98.170.57.231"

Au final ce seront moins de 200 ips qui seront ainsi bloquées, mais responsables d'environ 1,5M de requêtes à minima (entre celles qui sont arrivées jusqu'au serveur et celles bloquées sur CloudFlare).


Conclusion

Au final on se rends facilement compte qu'il est indispensable de pouvoir contrôler tous les éléments de son réseau ou de son infrastructure. Dans l'attaque présentée ici mon impossibilité d'agir au niveau des proxy Ezoic a engendré un énorme handicap et je dirai même une faille de sécurité. Ne parlons même pas de leur incapacité à fournir une liste courte et fiable de la liste d'IPs de leurs proxy que l'on pourrait utiliser avec le mod remote_ip d'Apache, ou encore l'absence d'un en-tête donnant l'IP du visiteur comme le fait Cloudflare avec CF-Connecting-IP.

Pour tous ceux qui utilisent Ezoic (libre à vous de le faire, de nombreux clients l'utilisent) faites le en déclarant au préalable votre site sur Cloudflare. Puis de là ajouter l'appli Ezoic. Ainsi vous pourrez faire un premier filtrage au niveau de Cloudflare, qui fournit d'excellents outils pour sécuriser son site. Vous pourrez utiliser l'API de Cloudflare pour bloquer directement des IPs que vous aurez détecté avec CrowdSec (ou un autre produit similaire). Vous aurez également les infos de la part de Cloudflare avec le bon en-tête pour récupérer l'IP du visiteur. Vous ne pourrez pas utiliser le mod remote_ip d'Apache car ce sont les IPs des proxy Ezoic qui se connecteront à vos serveurs, mais vous aurez au moins la partie CF-Connecting-IP.

Et si vous souhaitez découvrir plus en détail CrowdSec n'hésitez pas à venir sur leur Discord. Les devs se feront un plaisir de vous accompagner.

Dans tous les cas Cloudflare et Crowdsec sont 2 outils essentiels pour protéger votre site internet. Les 2 outils utilisé ensembles font un excellent travail. Sans parler du fait que vous pouvez faire cela gratuitement. En effet les solutions gratuites proposées pour ces 2 produits sont parfaitement suffisantes pour faire le job.