De nos jours, les serveurs accessibles par Internet sont la cible permanente d'attaques par bruteforce. C'est typiquement le cas de l'accès SSH qui, sans mesure de sécurité particulière, verra des centaines de connexions par minute pour bruteforcer le mot de passe d'utilisateurs tels que « root » ou « test ». LA solution à ces attaques sous Linux, c'est Fail2ban. Il y a des centaines d'articles sur le sujet, mais peu sur comment le configurer pour Shorewall.

Fail2ban

Pour faire simple (parce que c'est simple), Fail2ban c'est un logiciel en Python qui analyse les fichiers de logs et déclenche des actions si il y trouve des choses suspectes. Exemple typique : au bout de 5 messages de log correspondant à ^%(__prefix_line)sAuthentication failure for .* from <HOST>$ dans le fichier /var/log/auth.log, Fail2ban déclenche le blocage de l'IP <HOST>. Puis 10 minutes plus tard, Fail2ban déclenche l'action de déblocage de cette même IP.

La grande force de Fail2ban, c'est sa modularité. Finalement, il ne fait que chercher des expressions régulières dans des fichiers de logs, et exécuter un script lorsqu'une expression régulière est trouvée un certain nombre de fois dans une certaine période de temps, puis exécuter un autre script un certain temps après le premier.

Sur la plupart des distributions, Fail2ban est livré avec toute la configuration nécessaire pour le faire discuter avec iptables, mais nous utilisons Shorewall, une surcouche à iptables qui « empêche » de le configurer directement sous peine de perdre les modifications au moindre rechargement de Shorewall. La généricité de Fail2ban va tout de même nous permettre de le connecter à Shorewall.

Fail2ban + Shorewall

Le principe de base est simple, shorewall propose 2 commandes parfaites faites pour nous : shorewall drop <ip> et shorewall allow <ip>. Elles font exactement ce qu'elles laissent imaginer.

D'ailleurs, sous Debian, Fail2ban est aussi livré avec une action shorewall : /etc/fail2ban/shorewall.conf. Pour l'utiliser, il suffit simplement de préciser action=shorewall dans /etc/fail2ban/jail.local, et vous êtes bons.

Alors si c'est aussi simple, pourquoi écrire un article dessus ? Parce que, malheureusement, cette configuration ne suffit que pour les cas simples.

Gestion du multiban

Le multiban, c'est une manière de « bannir les bannis ». Ça permet d'avoir une escalade dans le blocage. Sans cette technique, on se retrouverait très souvent dans cette situation :

  • 10.42.42.356 fait 3 tentatives sur SSH et se retrouve bloquée 10 minutes
  • 10 minutes plus tard, l'IP est débloquée, mais recommence à attaquer
  • 3 tentatives, l'IP est à nouveau bloquée 10 minutes
  • 10 minutes plus tard, l'IP est débloquée, mais recommence à attaquer
  • 3 tentatives, l'IP est à nouveau bloquée 10 minutes

On ne s'en sort pas. L'idée du multiban, c'est de détecter ce schéma pour bloquer l'IP non pas 10 minutes, mais 1h, ou 1 semaine, puisqu'il ne fait plus aucun doute qu'il s'agit d'un attaquant et pas d'une erreur d'un utilisateur.

Une bonne façon d'implémenter ça, c'est de surveiller le fichier /var/log/fail2ban.log, qui référence religieusement chaque blocage et déblocage. Nicolargo présente très bien cette technique sur son blog : Bannir les bannis avec Fail2ban.

Mais cette technique ne marche qu'avec iptables, car il faut pouvoir préciser au parefeu le « nom du blocage ». Regardez le jail.conf proposé sur cet article : action = iptables[name=SSH,…]. Ce nom va mettre l'IP dans une chaine iptables dédiée à cette règle Fail2ban : iptables -I fail2ban-SSH -s <ip> -j DROP.

Dans le cas de Shorewall, nous n'avons que shorewall drop <ip>, nous ne pouvons pas préciser de chaine, seulement bloquer ou débloquer une IP, et ça a un effet de bord très ennuyeux :

  • 10.42.42.356 fait 3 tentatives sur SSH, et se retrouve bloquée 10 minutes
  • 10 minutes plus tard, l'IP est débloquée, mais recommence à attaquer
  • 3 tentatives, l'IP est à nouveau bloquée 10 minutes
  • 10 minutes plus tard, l'IP est débloquée, mais recommence à attaquer
  • 3 tentatives, l'IP est à nouveau bloquée 10 minutes
  • L'IP ayant été bloquée 3 fois dans fail2ban.log, elle est bloquée 1h par multiban
  • 10 minutes plus tard, l'IP est débloquée… Oups !

Contrairement à iptables, Shorewall ne sait pas faire la différence entre un blocage pour ban et un blocage pour multiban. Donc quand il débloque l'IP à la fin du ban, il débloque aussi le multiban.

La solution, c'est un wrapper que nous avons développé et qui permet de garder un compte du nombre de demandes de blocage et de déblocage de Fail2ban. Ainsi, si Fail2ban a bloqué 2 fois une IP (ban + multiban), et ne l'a débloquée qu'une fois (le ban expire, mais pas encore le multiban), l'IP restera bannie jusqu'à ce que le compteur revienne à zéro. Voici le script :

Configuration finale

Ne reste qu'à définir une action fail2ban pour l'appeler, dans /etc/fail2ban/action.d/shorewall-wrapper.conf :

#
# Author: Guillaume Subiron
#
# Ban IP using shorewall-drop-wrapper.sh
# https://gist.github.com/maethor/2661311b394c5a610a3d258e54d8ac2a
#

[Definition]

actionstart = 
actionstop = 
actioncheck = 
actionban = /usr/local/sbin/shorewall-drop-wrapper drop <ip>
actionunban = /usr/local/sbin/shorewall-drop-wrapper allow <ip>

Si ça n'est pas déjà fait, vous pouvez aussi définir le filtre ban dans /etc/fail2ban/filter.d/ban.conf :

# Ansible managed: modified on 2016-09-06 17:35:33 by gsubiron on infra-mon01
# Fail2Ban configuration file
#
# Author: Nicolargo
#
[Definition]

# Option: failregex
# Filter Ban in the fail2ban.log

failregex = .*\ Ban\ <HOST>

# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

Et enfin remplacer shorewall par shorewall-wrapper comme action dans le jail.conf (ou le jail.local) :

[ssh]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 6
action   = shorewall-wrapper

# Multi Ban
# 3 ban in 3 hour > Ban for 1 hour
[multi-ban]
enabled = true
filter = ban
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 14400
action = shorewall-wrapper
bantime = 3600

À suivre

Passée cette petite astuce et cet exemple simple en guise d'introduction, Fail2ban est au cœur de la politique de sécurité que nous mettons en place sur nos serveurs et ceux de nos clients. Dans un prochain article, nous détaillerons l'ensemble de notre jail.local et de nos filtres.

À propos de l'auteur



Guillaume est l'un des deux fondateurs et cogérants de Sysnove. Développeur Python et administrateur système passionné de logiciel libre et des technologies liées à Internet, il participe à divers projets, notamment le fournisseur d'accès Internet Aquilenet ainsi que la Fédération FDN.

Chez Sysnove, son rôle consiste à mettre en place et administrer les infrastructures nécessaires à l'hébergement des services fournis aux clients. En tant que directeur général, il gère aussi les aspects administratifs de l'entreprise.