Fail2ban : créer un filtre pour bloquer les attaques DoS ou bruteforce

Bloqueur de pub détectée - Vous bloquez l'affichage des publicités.
Pour soutenir le site, merci de bien vouloir laisser les publicités s'afficher
Plus d'informations : Comment désactiver les bloqueurs de publicité sur un site internet

Dans l'article précédent, je présentais le fonctionnement de fail2ban : Fail2ban : protéger son serveur des attaques DoS et Bruteforce.
Ce service scrute les logs et détecte certains comportement malveillants afin de bannir l'adresse IP.

Mais comment créer son propre filtre pour bloquer certaines attaques ou occurrences avec fail2ban ?

Dans cet article, voici toutes explications pour créer un filtre sur fail2ban et le mettre en place afin de protéger son serveur WEB des attaques par déni de service (DoS).

Fail2ban : créer un filtre pour bloquer les attaques DoS ou bruteforce

Fail2ban : créer un filtre pour bloquer les attaques DoS ou bruteforce

fail2ban fournit pas mal de prisons pour la plupart des services réseaux (HTTP, SMTP, SSH, etc).
Mais parfois, on peut être confronté à des situations qui nécessitent des actions, comportements ou attaques alors que les filtres ne sont pas disponibles.
Dans ces cas là, il faut créer son propre filtre fail2ban.
Pour cela, il faut maitriser un peu regex puisque c'est la base pour faire reconnaître un pattern à fail2ban.

Voici un serveur WEB (sous LighHTTP) avec pas mal de requêtes provenant d'IP dont le serveur WEB retourne un code HTTP 416.
On souhaite bannir les IP qui bouclent trop sur ce code car on estime qu'il y en a trop.
Voici un exemple, en XX.XX c'est l'IP du serveur WEB que j'ai masqué.

# 217.64.107.201 XX.XX.XX.XX - [10/Nov/2020:22:03:57 +0000] "GET /XXXXX
HTTP/1.1" 416 385 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36"

Ce qui donne par exemple ceci dans les logs LighHTTP :

Les logs HTTP avec les attaques bruteforce et DoS

Pour y parvenir :

  • il faudra créer un filtre qui permet de détecter ces connexions HTTP
  • puis un fichier de prison pour configurer les actions à mener avec ses paramètres

Créer le filtre

On commence donc par créer le filtre suivant /etc/fail2ban/filter.d/lighttpd-406.conf :

[Definition]
datepattern = ^[^\[]*\[({DATE})
               {^LN-BEG}
failregex = ^<HOST> XX\.XX\.XX\.XX - \[.*] "GET.*HTTP\/1.1" 416 385
ignoreregex =
  • datepattern permet de configurer le foramt des dates utilisées dans les logs du serveur WEB
  • ^<HOST> c'est l'IP que l'on souhaite bannir. Ce paramètre est obligatoire sinon le filtre ne fonctionnera pas
  • puis le regex pour encadrer le contenu que l'on veut matcher

Si vous ne spécifiez pas HOST alors fail2ban retournera l'erreur suivant : ERROR: No failure-id group" from fail2ban-regex on custom filter.

Tester le filtre avec fail2ban-regex

Il est tout à fait possible de tester notre filtre avec une ligne d'exemple grâce à fail2ban-regex.
On lui donne la ligne à tester tout en spécifiant le filtre ou le fichier de logs, soit donc les syntaxes suivantes

fail2ban-regex 'le contenu a tester' /etc/fail2ban/filter.d/lighttpd-406.conf

ou via les logs :

fail2ban-regex /var/log/lighttpd/access.log /etc/fail2ban/filter.d/lighttpd-406.conf

Ce qui donne le test suivant :

fail2ban-regex '217.64.107.201 1.2.3.4 - [10/Nov/2020:22:03:57] "GET /XXX HTTP/1.1" 416 385 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36' /etc/fail2ban/filter.d/lighttpd-406.conf

Lorsque le filtre fonctionne matched est à 1, sinon il est ignoré ou manqué (missed).
La portion qui ne match pas est alors indiquée pour correction.

Tester un filtre avec fail2ban-regex

Ajustez votre filtre jusqu'à ce qu'il matche le contenu à bannir.

Créer la prison

Une fois que votre filtre fonctionne, il ne reste plus qu'à configurer la prison.
Pour cela, on créé le fichier de configuration de la prison avec sa zone.
Il se trouve dans /etc/fail2ban/jail.d/lighttp.conf avec ce contenu qui reprend l'exemple précédent.

[lighttpd-406]
enabled = true
filter = lighttpd-406
action   = iptables-ipset-proto4[name=blacklist, port="http,https", protocol=tcp, bantime=0]
logpath = /var/log/lighttpd/access.log
findtime = 600
bantime = 7200
maxretry = 4

On utilise donc le filtre lighttpd-406 et un bannissement par Ipset.
Le reste a déjà évoqué.

Vous pouvez laisser l'action vide afin qu'il ne fasse rien, cela permet de tester la prison sur le long terme en production sans bannir personne.

Enfin il ne reste plus qu'à relancer le service fail2ban :

/etc/init.d/fail2ban reload

Quand cela fonctionne fail2ban détecte et ban les IP.

Détection d'attaque et bannissement par fail2ban

Ce qui permet de faire tomber le nombre de requêtes par secondes sur le serveur WEB.
Ces graphiques munin le confirment après mise en place.

Les graphiques Munin montre une baisse des requêtes WEB grâce à la protection fail2ban
Les graphiques Munin montre une baisse du trafic réseau grâce à la protection fail2ban

Enfin le graph munin de la prison fail2ban :

Grapher fail2ban sur munin pour monitorer les prisons fail2ban

Créer un filtre pour bloquer une attaque DoS L7

Voici un autre exemple avec une attaque DoS Layer 7 sur un serveur WEB.
On peut créer une règle pour gérer celle-ci.

L'étude de l'attaque DoS

Comprenez qu'une attaque DoS, c'est un envoie de commandes à un botnet.
En clair donc tous reçoivent le même ordre et la même action est menée.
Elle peut-être plus ou moins sophistiquée mais en général, la demande de ressources à la page est assez identique.
On peut donc dégager un pattern qui permet de reconnaître l'attaque d'une requête WEB saine.
A partir de là, il est possible de créer une règle fail2ban pour bloquer et bannir les IP.

Ici, on voit que :

  • C'est toujours la même page WEB qui est demanée
  • Le user-agent est aléatoire
  • le référer est aléatoire mais pris dans une liste 4/5 sites (facebook, qq, google, youtube).
Exemple d'une attaque par déni de service (DoS) L7

On ne peut pas bloquer les requêtes depuis ces referer car sinon on bloquerait aussi du trafic légitime.

Maintenant, est-ce normal d'avoir plusieurs requêtes WEB d'une IP avec une referer ?
La réponse est non.
En général, c'est plutôt, je viens de Google, Youtube ou d'un site WEB puis je navigue dans le site (et donc plus de referer ou lui même).

Ici on cherche à bloquer l'attaque avec fail2ban, ce n'est pas forcément la meilleure solution, on peut très bien mettre un filtre JS ou Captcha avec Cloudflare sur la page visée.
C'est plus une excuse ici pour montrer jusqu'où on peut aller avec les filtres fail2ban.

Créer le filtre fail2ban en réponse

Ainsi, il est tout à fait possible de créer un filtre qui bloque trop de requêtes en un espace de temps limité avec un referer.

Il faut :

  • Bloquer toutes les requêtes avec un referer SAUF notre site où aucun referer
  • Viser que les pages PHP ou qui se terminent par /. C'est le cas des pages WordPress de mon site : https://www.malekal.com/super-article-de-ouf/
  • Il ne faut pas que ce soit des images.. en effet, quand on parcoure un google images, on peut avoir plusieurs requêtes d'affilés avec Google. Cela bloquerait du trafic légitime
  • On peut exclure certains domaines en referer.

Voici à quoi cela peut ressembler.
En haut on a en commentaire des requêtes illégitimes issues de l'attaques DoS.

#109.105.205.186 - - [13/Nov/2020:13:44:34 +0100] "GET /viewtopic.php?f=2&t=67342 HTTP/1.1" 403 571 "https://www.qq.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
#109.238.208.130 - - [13/Nov/2020:13:44:35 +0100] "GET /viewtopic.php?f=2&t=67342 HTTP/1.1" 403 169 "https://www.reddit.com" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1"

[Definition]
datepattern = ^[^\[]*\[({DATE})
               {^LN-BEG}
failregex = ^<HOST> - - \[.*] "(GET|POST|HEAD) \/[a-z0-9_-]+(\.php|\/)(\?[a-z0-9=&]+)? HTTP\/[0-9]\.[0-9]" [0-9]{3} [0-9]{1,5} "https?:\/\/(?![a-z]+\.(malekal|commentcamarche[supprimer-trojan)\.(com|net))
ignoreregex =

Les explications du failregex.

  • On récupère l'HOST du client
  • puis on encadre la date de la requête avec [.*]... on pourrait ici améliorer le regex pour le réduire
  • Ensuite la méthode HTTP
  • puis la page demandée, là ça se complexifie un peu.
    • \/[a-z0-9_-]+(.php|\/) : n'importe quelle page PHP ou qui se termine par /. Cela exclut ainsi toutes les images .jpg, .png, etc.
    • (\?[a-z0-9=&]+)? : puis on autorise les paramètres de la page PHP souvent ?parametres=valeur si présent avec le ? à la fin car ce n'est pas obligatoire
  • Puis on encadre la version HTTP : HTTP\/[0-9].[0-9]"
  • Le code HTTP et la taille de la page [0-9]{3} [0-9]{1,5}
  • Enfin le referer :
    • "https?:\/\/ ce sera donc une page sécurisée. Cela exclut les requêtes avec un referer vide
    • (?![a-z]+.(malekal|commentcamarche|supprimer-trojan).(com|net)) permet d'exclure notre site et commentcamarche.
Je rappelle qu'en regex les exclusions sont de la forme (?!Pattern).

Il ne reste plus qu'à tester les combinaisons avec fail2ban-regex.
On voit bien que cela répond à nos attentes.

Tester le filtre fail2ban fasse à une attaque DoS

Il ne reste plus qu'à tester en pratique.
Pour cela, j'ai fait une vidéo.

Le filtre fail2ban maison fonctionne à la perfection.
Mais ici le problème est que l'action est CloudFlare.
En effet, on peut utiliser l'API pour les bannir sur CloudFlare mais cet envoie se fait par curl et c'est très lent.
Ainsi pour bannir l'intégralité des attaques, soit environ 400 IP, il a fallu plusieurs minutes.
Ce n'est donc pas très réactif.
Par contre avec une action de type ipset, cela doit permettre de bloquer l'attaque par deni de service.

Fail2ban a banni toutes les IP attaquantes, un peu de plus de 400.

Lister les IP d'une prison avec fail2ban-client

On les retrouve bien aussi sur CloudFlare.
Du coup, si l'attaque se reproduit, CloudFlare l'a bloquera en amont du serveur WEB.

Les IP bannies de fail2ban sur Cloudflare

Bon bien sûr, c'est un exemple de ce que l'on peut faire avec fail2ban.
Pour une attaque DoS plus conséquente ou plus sophistiqués, cela ne fonctionnera pas.

Bravo ! vous avez réussi à bloquer et protéger votre serveur WEB d'une attaque par déni de service (DoS).

Liens

Vous avez trouvé cet article utile et interressant, n'hésitez pas à le partager...

Trouver la solution sur le forum d'aide

Vous êtes arrivé au terme de l'article Fail2ban : créer un filtre pour bloquer les attaques DoS ou bruteforce mais vous n'avez pas trouvé la solution à votre problème...
Suivez ces articles du forum pour trouver une réponse ou demandez à votre tour de l'aide sur le forum