Pas Tout A Fait

Aller au contenu | Aller au menu | Aller à la recherche

Protéger un serveur avec Fail2ban

Dernière mise à jour le 04 juillet 2014

Parmi les indispensables pour sécuriser un serveur sous GNU/Linux, on trouve le logiciel Fail2ban, qui, pour faire simple, lit les fichiers de log du système et bannit les adresses IP qui ont obtenu un trop grand nombre d'échecs lors de l'authentification. Il met à jour les règles du pare-feu pour rejeter ces adresses IP pour une durée paramétrable. C'est un logiciel libre publié sous licence GPL v2 et écrit avec le langage Python.

fail2ban_logo.png


Installation

La dernière version de Fail2ban, numéro 0.8.6, a été publiée en novembre 2011.
Pour l'installer sous Debian et Ubuntu :

apt-get install fail2ban

Et voilà.


Configuration

Le répertoire contenant les fichiers de configuration est "/etc/fail2ban/". Le daemon se lance et s'arrête avec les classiques "/etc/init.d/fail2ban start" et "/etc/init.d/fail2ban stop". Vous pouvez recharger la configuration avec la commande "fail2ban-client reload" et afficher l'état du daemon avec "fail2ban-server status".

Le fichier contenant les logs de fail2ban est par défaut "/var/log/fail2ban.log".
Ce fichier de log est analyser par défaut par LogWatch, ce qui permet d'obtenir un rapport régulier de l'activité de Fail2ban. Il est également possible d'analyser ces logs avec les commandes awk et grep (voir http://www.the-art-of-web.com/system/fail2ban-log/).

Le répertoire "/etc/fail2ban/" contient le fichier "fail2ban.conf", qui permet de spécifier le niveau des logs et le fichier où les enregistrer ainsi que le socket, le fichier "jail.conf", qui permet de définir les prisons (jail donc), et les répertoires "action.d/" et "filter.d/".

Pour bien comprendre le fonctionnement de fail2ban :

  • Un filtre est une expression rationnelle qui doit "matcher" les erreurs d'identifications ou tout autre motif.
  • Une action est une ou plusieurs commandes à exécuter à un moment défini.
  • Une prison est l'association d'un filtre avec une ou plusieurs actions. Fail2ban peut gérer de multiples prisons.
Le fichier jail.conf

Avant de commencer, il est préférable de créer le fichier "/etc/fail2ban/jail.local" (en copiant simplement le fichier jail.conf avec un cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local) et d'éditer directement ce fichier plutôt que jail.conf.

Ce fichier est visualisable en trois sections :

  • Default
  • Actions
  • Jail

Dans la section "default" et "actions" on trouve des paramètres et leurs valeurs par défaut, ces valeurs pouvant être supplantées par celles précisées dans les prisons.

Les options générales par défaut sont :

  • IgnoreIP qui permet de définir des IP à ignorer totalement, séparées par un espace
ignoreip = 127.0.0.1 88.172.211.165
  • bantime qui définit en secondes le temps de blocage par défaut des prisons
bantime  = 3600
  • maxretry qui détermine le nombre d'échecs autorisés avant de bloquer une IP
maxretry = 3
  • backend qui spécifie le backend utilisé pour obtenir les modifications de fichiers.
backend = polling
  • destmail pour indiquer l'adresse mail de destination des messages envoyés par fail2ban

destemail = mpatout@pastoutafait.org

Les actions par défaut sont :

  • banaction qui définit l'action par défaut à utiliser
banaction = iptables-multiport
  • mta pour définir le MTA à utiliser
mta = sendmail
  • protocol indique le protocole sur lequel agir par défaut
protocol = tcp
  • action permet de définir le comportement de l'action par défaut, en utilisant éventuellement les raccourcis "action_" , "action_mw" ou "action_mwl" (respectivement interdiction simple, interdiction avec envoi d'un mail contenant un whois de l'adresse bannie, et interdiction avec mail contenant whois et lignes de logs ayant provoqué le bannissement).
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]
              %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s]
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]
               %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s]
action = %(action_)s

Arrive ensuite le gros morceau, la définition des prisons.
Une prison utilise la structure suivante :

[proftpd]

enabled  = false
port	 = ftp,ftp-data,ftps,ftps-data
filter   = proftpd
logpath  = /var/log/proftpd/proftpd.log
maxretry = 6

Voici la liste des principales options :

  • enabled avec pour valeur true ou false permet d'activer ou pas la prison
  • port indique les ports TCP surveillés, par leur numéro ou nom
  • filter définit le nom du filtre à utiliser
  • action définit l'action à réaliser
    • servicemail permet l'envoi d'un mail d'alerte
  • logpath indique le chemin du fichier de logs à analyser
  • maxretry définit le nombre de tentatives possibles avant l'interdiction
  • finstime définit le temps en seconde durant lequel les tentatives peuvent être accumulées
  • bantime définit la durée de l'interdiction

Encore une fois, si une option n'est pas définie dans la prison, c'est la valeur par défaut qui sera utilisée.

Les fichiers de filtre

Voici un exemple de fichier filtre contenu dans le répertoire "/etc/fail2ban/filter.d/", vsftpd.conf :

[Definition]

failregex = vsftpd(?:\(pam_unix\))?(?:\[\d+\])?:.* authentication failure; .* rhost=<HOST>(?:\s+user=\S*)?\s*$
            \[.+\] FAIL LOGIN: Client "<HOST>"\s*$

ignoreregex =

Une chose à définir dans tous les cas, la valeur de "failregex". Il s'agit d'une expression rationnelle devant "matcher" les erreurs dans les fichiers de logs.

Il est possible d'utiliser "ignoreregex" pour spécifier une autre expression rationnelle, celle-ci précisant des lignes de logs à ignorer.

Vous disposez de la commande "fail2ban-regex" pour tester vos expressions rationnelles. Cette commande demande deux paramètres, une ligne de log type, et l'expression à tester sur cette ligne de log, par exemple :

#fail2ban-regex '213.246.51.20 - - [28/Feb/2012:05:10:24 +0100] "GET //phpmyadmin.old/main.php HTTP/1.1" 301 178 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"' '<HOST> - - \[.*?\] ".*(PMA|phpmyadmin|myadmin|mysql|mysqladmin|sqladmin|mypma|admin|xampp|mysqldb|mydb|db|dbadmin|pmadb|phpmyadmin1|myadmin2).*" 301 .*'

Running tests
=============

Use regex line : <HOST> - - \[.*?\] ".*(PMA|phpmyadmin|myadmin|mysq...
Use single line: 213.246.51.20 - - [28/Feb/2012:05:10:24 +0100] "GE...

Results
=======

Failregex
|- Regular expressions:
|  [1] <HOST> - - \[.*?\] ".*(PMA|phpmyadmin|myadmin|mysql|mysqladmin|sqladmin|mypma|admin|xampp|mysqldb|mydb|db|dbadmin|pmadb|phpmyadmin1|myadmin2).*" 301 .*
|
`- Number of matches:
   [1] 1 match(es)

Ignoreregex
|- Regular expressions:
|
`- Number of matches:

Summary
=======

Addresses found:
[1]
    213.246.51.20 (Tue Feb 28 05:10:24 2012)

Date template hits:
0 hit(s): MONTH Day Hour:Minute:Second
0 hit(s): WEEKDAY MONTH Day Hour:Minute:Second Year
0 hit(s): WEEKDAY MONTH Day Hour:Minute:Second
0 hit(s): Year/Month/Day Hour:Minute:Second
0 hit(s): Day/Month/Year Hour:Minute:Second
0 hit(s): Day/Month/Year Hour:Minute:Second
2 hit(s): Day/MONTH/Year:Hour:Minute:Second
0 hit(s): Month/Day/Year:Hour:Minute:Second
0 hit(s): Year-Month-Day Hour:Minute:Second
0 hit(s): Day-MONTH-Year Hour:Minute:Second[.Millisecond]
0 hit(s): Day-Month-Year Hour:Minute:Second
0 hit(s): TAI64N
0 hit(s): Epoch
0 hit(s): ISO 8601
0 hit(s): Hour:Minute:Second
0 hit(s): <Month/Day/Year@Hour:Minute:Second>

Success, the total number of match is 1

However, look at the above section 'Running tests' which could contain important
information.

Un outil tout simple qui dépanne bien !

Les fichiers d'action

Voici un exemple de fichier "action", contenu dans le répertoire "/etc/fail2ban/action.d/". Il s'agit de "iptables.conf" :

[Definition]

# Notes.:  command executed once at the start of Fail2Ban.
actionstart = iptables -N fail2ban-<name>
              iptables -A fail2ban-<name> -j RETURN
              iptables -I INPUT -p <protocol> --dport <port> -j fail2ban-<name>

# Notes.:  command executed once at the end of Fail2Ban
actionstop = iptables -D INPUT -p <protocol> --dport <port> -j fail2ban-<name>
             iptables -F fail2ban-<name>
             iptables -X fail2ban-<name>

# Notes.:  command executed once before each actionban command
actioncheck = iptables -n -L INPUT | grep -q fail2ban-<name>

# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP

# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP

[Init]

# Defaut name of the chain
name = default

# Notes.:  specifies port to monitor
port = ssh

# Notes.:  default protocol, internally used by config reader for interpolations.
protocol = tcp

Si vous connaissez un minimum IPTables, vous ne devez pas être dépaysé par ce fichier, qui contient simplement les commandes à effectuer au démarrage et à l'arrêt de Fail2ban, les commandes pour bloquer et débloquer un IP, ainsi que quelques variables comme le nom de la chaine IPTables et éventuellement le couple protocole / port à cibler.

Les fichiers actions fournis avec l'installation de base sont bien suffisants pour la majorité des utilisations.


Utilisation

Pour une utilisation standard et déjà efficace, il suffit de démarrer fail2ban !

Les filtres et actions de base sont remarquables, et englobent la majorité des services que l'on trouve communément sur les serveurs.

Afficher la liste des IP interdites

Afficher la liste des adresses IP bloquée est possible en affichant la liste des règles IPTables en cours, avec la commande suivante :

iptables -L

Vous pourrez observer des lignes de ce genre :

Chain fail2ban-nginx404 (1 references)
target     prot opt source               destination         
DROP       all  --  lns-bzn-45-82-65-131-40.adsl.proxad.net  anywhere

Ici l'IP 82.65.131.40 (désignée par son reverse DNS "lns-bzn-45-82-65-131-40.adsl.proxad.net") est bloquée par le filtre nommé "fail2ban-nginx404".

Vous pouvez également afficher les prisons actives avec la commande :

fail2ban-client status

Et afficher l'activité d'une prison active avec :

fail2ban-client status nomdelaprison
Supprimer une IP de la liste

Pour supprimer une adresse bloquée de la liste, on utilise une fois de plus IPTables, avec par exemple une commande comme ci-dessous pour débloquer l'IP 82.65.131.40 :

iptables -D fail2ban-nginx404 -s lns-bzn-45-82-65-131-40.adsl.proxad.net -j DROP

Notez qu'avec cette méthode, Fail2ban considérera toujours cette adresse comme bloquée, puisque nous avons outrepassé l'action de Fail2ban en débloquant le vilain. Il va d'ailleurs râler (sans conséquence) dans ses logs au moment du déblocage :

2001-08-01 01:56:30,861 fail2ban.actions.action: ERROR  iptables -D fail2ban-nginx40x -s 82.65.131.40 -j DROP returned 100
Savoir quelle ligne de log provoque un blocage

Il peut être intéressant de connaître la ligne de log ayant provoqué un blocage. Pour faire cela par défaut, il faut dans le fichier "/etc/fail2ban/jail.conf" ajouter la ligne suivante :

action = %(action_mwl)s

Pour limiter cette action à quelques règles particulières, il est préférable d'utiliser une ligne directement dans le bloc de configuration d'une prison, par exemple avec :

[nginx-404]

...
action   = iptables[name=nginx404, port=http, protocol=tcp]
                sendmail-whois-lines[name=nginx-404, lines=5, dest=address@domain.tld]
...

Si jamais le mail envoyé contient une ligne :

Lines containing IP:1.2.3.4 in /dev/null

Vous pouvez essayer de spécifier les fichiers de logs dans l'action :

[nginx-40x]

...
action   = iptables[name=nginx404, port=http, protocol=tcp]
                sendmail-whois-lines[logpath=/var/log/nginx/*access_log, name=nginx-404, lines=5, dest=address@domain.tld]
...
Mettre en liste blanche une IP / un réseau

Vous pouvez aisément empêcher le blocage des IPs de votre réseau en ajoutant dans le fichier "/etc/fail2ban/jail.local" ceci :

ignoreip = 192.168.0.0/24

Il est évidemment possible de n'indiquer qu'une seul adresse :

ignoreip = 126.32.52.48
Filtrer Fail2ban

Si une IP est bloquée/débloquée à longueur de journée, il est utile d'aller analyser les logs de fail2ban pour la débusquer, et la bloquer pour une plus longue période.

Créez le fichier /etc/fail2ban/filter.d/fail2ban.conf et ajoutez-y ceci :

# Filtre Fail2ban
[Definition]
failregex = fail2ban.actions: WARNING \[(.*)\] Ban <HOST>
ignoreregex = fail2ban.actions: WARNING \[fail2ban\] Ban <HOST>

Et dans jail.local :

[fail2ban]
enabled = true
filter = fail2ban
action = iptables-allports[name=fail2ban]
sendmail-whois[dest="votre@mail.com",name="fail2ban",sender="fail2ban"]
# Fichier de log de fail2ban :
logpath = /var/log/fail2ban.log
# Analyse les logs sur 1 semaine
findtime = 604800
# bantime : 1 semaine
bantime = 604800
# ou bantime : 1 mois
# bantime = 2678400

Cette prison ne fonctionne pas avec les actions qui enregistrent l'adresse IP bannie une seul fois, sans garder trace de la prison qui provoque cette interdiction.

Par exemple, quand un vilain est bloqué suite à des erreurs de mots de passe SSH, pour la troisième fois de la journée, la prison SSH interdit donc son IP une troisième fois pour une durée de 10 minutes.

Quelques secondes après ce troisième blocage, la prison Fail2ban bloque ce vilain pour une durée beaucoup plus longue (une semaine dans notre code ci-dessus). Mais l'IP du vilain est déjà dans la liste des adresses bloquées, et Fail2ban ne fait pas la différence entre les différentes prisons.

Après 10 minutes, la prison SSH retire l'interdiction qu'elle a posée, et n'ayant pas connaissance de l'interdiction mise en place par la prison Fail2ban, elle retire l'IP de la liste des adresses interdites. Cette IP est donc à nouveau autorisée, malgré la prison Fail2ban qui devait la bloquer pour une longue période.

Ce problème se présente avec les actions suivantes : ipfw, hostsdeny et shorewall, qui n'enregistre que l'IP sans le nom de la prison.

Une solution pour le contourner est d'utiliser des actions différentes pour bloquer avec les prisons Fail2ban et SSH.

Problème fréquent avec de multiple prisons

Il arrive souvent que lors d'un démarrage/redémarrage, Fail2ban (dans sa version v0.8.4, celle présente dans les dépôts Debian à l'heure ou j'écris ces lignes) ponde des erreurs de ce genre dans ses logs :

iptables -I INPUT -p tcp -m multiport --dports ssh -j fail2ban-ssh-ddos returned 200
iptables -A fail2ban-ssh-ddos -j RETURN
2012-03-01 21:56:43,407 fail2ban.actions.action: ERROR  iptables -N fail2ban-ssh-ddos

Pour ne plus rencontrer ce type d'erreur, il faut modifier le fichier "/usr/bin/fail2ban-client" :

def __processCmd(self, cmd, showRet = True):
beautifier = Beautifier()
for c in cmd:
time.sleep(0.1)
beautifier.setInputCmd(c)

Augmentez la valeur de time.sleep en mettant par exemple (0.2).

Notez que cette solution n'est pas fonctionnelle chez tout le monde... Un rapport de bug existe, et un patch résolvant le problème est incorporé dans la version v0.8.5.


Voilà, vous connaissez maintenant pas mal de choses sur Fail2ban et son fonctionnement. Il s'agit d'un outil puissant, très modulable et performant. Pour les amateur d'interface Web, il existe le projet Fail2Web pour administrer Fail2Ban.

Vous pouvez étudier un exemple simple de mise en place d'une prison avec un filtre spécifique dans le billet filtrer les erreurs 404 avec Fail2ban et NGinx.

Et si vous voulez allez plus loin dans la sécurisation de votre machine, et que Fail2ban ne répond pas à vos attentes, vous pouvez vous tourner vers OSSEC.

Sources :
gardouilleland.free.fr/
technique.arscenic.org/
www.fail2ban.org/

Matthieu Patout

Auteur: Matthieu Patout

Restez au courant de l'actualité et abonnez-vous au Flux RSS

Les commentaires sont fermés


aucune annexe



Voir Aussi

torchat-logo.png

Messagerie instantanée sécurisée avec TorChat

Plusieurs solutions existent pour sécuriser les communications de messagerie instantanée. Il s'agit...

Lire la suite

hacker-rip.jpg

Vérifier l'intégrité d'un système de fichiers avec Integrit

Une bonne habitude pour surveiller qu'un serveur n'est pas compromis consiste à utiliser une...

Lire la suite