Table des matières
Réaction dynamique : fail2ban
Nous allons continuer avec ssh
, mais dans d'autres conditions.
Nous considérons que le port 22 ne peut être modifié, ce qui nous rapprochera du cas d'autres protocoles comme http
, imap
, smtp
. Ici, il n'est plus question de bloquer tout le monde mais seulement ceux qui commettent des actions frauduleuses, recherche d'un mot de passe en ce qui concerne notre exemple. Il nous faut donc un outil capable de :
- détecter une action malveillante ;
- agir dynamiquement sur le pare-feu en conséquence.
Fail2Ban
Cet outil répond aux besoins. Son principe est le suivant :
- il analyse certains fichiers de logs ;
- lorsqu'il y trouve un message signifiant une tentative frauduleuse, il réagit en bloquant l'adresse IP source.
Le tout est bien entendu configurable à souhait, ce qui en fait un outil pas si évident que ça à mettre en œuvre. La configuration par défaut peut cependant répondre à la plupart des cas, mais mieux vaut avoir bien compris le fonctionnement d cet outil.
Tout ce qui va suivre s'appuie sur la version 0.8.11, distribuée dans la Debian Jessie (à l'heure…) alors que la version 0.8.6 est fournie avec Wheezy.
Les prisons
Les « prisons » sont en fait des tables iptables qui seront ajoutées pour chaque protocole que l'on souhaite protéger. Fail2ban ajoutera dans ces tables des règles de bannissement de façon dynamique.
Il existe un fichier /etc/fail2ban/jail.conf
qui procure un certain nombre de prisons, seule la prison relative à ssh
est activée par défaut. Voyons ce qui est écrit concernant ssh
:
[ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 6
Le filtre est activé, il utilise un filtre nommé sshd
, il suit le log auth.log
et il va réagir si la même adresse IP source se manifeste 6 fois dans un intervalle de temps donné (que nous rechercherons plus tard).
Lorsque fail2ban
va démarrer, il va :
- créer une table nommée
fail2ban-ssh
; - y ajouter la règle
-j RETURN
- insérer en tête de
INPUT
une règle de type :-p tcp -m multiport –dports 22 -j fail2ban-ssh
;
Ce qui correspondrait à :
iptables -N fail2ban-ssh iptables -A fail2ban-ssh -j RETURN iptables -I INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
Lorsqu'une adresse IP aura été détectée comme appartenant au Mal, il ajoutera simplement :
iptable -A fail2ban-ssh -s 192.168.10.34/32 -j REJECT --reject-whth-icmp-port-unrecheable
Il supprimera cette règle au bout d'un « certain temps » dont nous rechercherons la valeur plus tard.
jail.conf
Il n'y a pas que des prisons définies dans ce fichier. Nous y trouvons aussi une section [DEFAULT]
qui va nous éclairer sur quelques points.
ignoreip = 127.0.0.1/8
Il y a possibilité de dire à fail2ban
d'ignorer certaines adresses IP ici, les adresses internes.
bantime = 600
Par défaut, un bannissement ne durera que 600 secondes (ce qui est peu)
findtime = 600
C'est l'intervalle de temps durant lequel la faute doit être constatée…
maxretry = 3
trois fois (par défaut) pour que le bannissement ait lieu. Nous avons vu que cette valeur a été portée à 6 pour ssh
dans la prison d'origine.
banaction = iptables-multiport
L'action à mener en cas de bannissement. Il faudra aller chercher ailleurs la définition de cette action.
Il y a d'autres paramètres intéressants comme action
, destmail
et sendermail
:
action
définit tout ce que faitfail2ban
en cas de constat d'infraction. En plus du bannissement, il peut - avoir un envoi d'e-mail, lequel peut contenir plus ou moins d'informations ;destmail
définit la ou les adresses des destinataires des e-mails d'alerte ;sendermail
définit l'adresse attribuée à l'émetteur de l'e-mail.
D'autres paramètres seraient intéressants à analyser, mais ne faisons pas tout à la fois.
Ces paramètres par défaut peuvent être surchargés dans chaque définition de prison. Il est tout à fait déconseillé d'agir sur le fichier jail.conf
qui est susceptible d'être modifié lors d'une mise à jour. La méthode la plus simple est de créer un jail.conf.local
. Il sera lu après jail.conf
et donc écrasera d'éventuelles valeurs par défaut. La méthode la plus « pédestre » consiste donc à :
- copier
jail.conf
versjail.conf.local
; - modifier selon ses besoins le
jail.conf.local
.
Dans Debian/jessie, selon la méthode qui tend à se répandre, un dépertoire jail.d
va permettre d'y stocker les différentes prisons que l'on souhaite activer, sous forme de fichiers distincts. Cette méthode est sans doute à préférer au jail.conf.local
.
Les filtres
il y a un dossier /etc/fail2ban/filter.d
qui contient une bibliothèque de filtres, dans laquelle nous retrouvons notre filtre sshd
dans le fichier sshd.conf
:
# Fail2Ban filter for openssh # [INCLUDES] # Read common prefixes. If any customizations available -- read them from # common.local before = common.conf [Definition] _daemon = sshd failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from <HOST>( via \S+)?\s*$ ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$ ^%(__prefix_line)sFailed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s(, client user ".*", client host ".*")?))?\s*$ ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$ ^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$ ^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers\s*$ ^%(__prefix_line)sUser .+ from <HOST> not allowed because listed in DenyUsers\s*$ ^%(__prefix_line)sUser .+ from <HOST> not allowed because not in any group\s*$ ^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$ ^%(__prefix_line)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*$ ^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$ ignoreregex = # DEV Notes: # # "Failed \S+ for .*? from <HOST>..." failregex uses non-greedy catch-all because # it is coming before use of <HOST> which is not hard-anchored at the end as well, # and later catch-all's could contain user-provided input, which need to be greedily # matched away first. # # Author: Cyril Jaquier, Yaroslav Halchenko, Petr Voralek, Daniel Black
Il s'agit principalement d'une liste d'expressions régulières destinées à identifier les messages intéressants dans le fichier de logs. Ces filtres sont généralement bien conçus, mis à jour dans la distribution en cas de besoin, il n'est donc pas conseillé de les modifier.
Notons que ce filtre en inclut un autre qui est lu avant et qui s'appelle common.conf
, lui-même pouvant charger après un éventuel common.conf.local
.
Vous le voyez, plus on fouille, plus on découvre que c'est compliqué, et ce n'est pas fini…
Les actions
De même que pour les filtres, nous avons un /etc/fail2ban/action.d
dans lequel nous allons retrouver notre banaction
par défaut iptables-multiport
sous la forme du fichier iptables-multiport.conf
:
# Fail2Ban configuration file # # Author: Cyril Jaquier # Modified by Yaroslav Halchenko for multiport banning # [INCLUDES] before = iptables-blocktype.conf # Il faudra en tenir compte, il est assez fondamental pour mieux comprendre [Definition] # Option: actionstart # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # actionstart = iptables -N fail2ban-<name> iptables -A fail2ban-<name> -j RETURN iptables -I <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name> # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name> iptables -F fail2ban-<name> iptables -X fail2ban-<name> # Option: actioncheck # Notes.: command executed once before each actionban command # Values: CMD # actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]' # Option: actionban # Notes.: command executed when banning an IP. Take care that the # command is executed with Fail2Ban user rights. # Tags: See jail.conf(5) man page # Values: CMD # actionban = iptables -I fail2ban-<name> 1 -s <ip> -j <blocktype> # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the # command is executed with Fail2Ban user rights. # Tags: See jail.conf(5) man page # Values: CMD # actionunban = iptables -D fail2ban-<name> -s <ip> -j <blocktype> [Init] # Default name of the chain # name = default # Option: port # Notes.: specifies port to monitor # Values: [ NUM | STRING ] Default: # port = ssh # Option: protocol # Notes.: internally used by config reader for interpolations. # Values: [ tcp | udp | icmp | all ] Default: tcp # protocol = tcp # Option: chain # Notes specifies the iptables chain to which the fail2ban rules should be # added # Values: STRING Default: INPUT chain = INPUTNous trouvons :
actionstart
qui décrit la table et les chaînes à ajouter au démarrage defail2ban
, telles que nous les avons vues plus haut avec des avec des paramètres entre < > ;actionstop
c'est bien quefail2ban
pense à faire le ménage lorsqu'on l'arrête ;actionban
qui ajoute dans la table concernée une règle qui va diriger l'adresse IP méchante vers quelque chose définie par<blocktype>
;actionunban
qui enlèvera ladite règle.
Pour savoir ce qu'est ce <blocltype>
, allons voir le contenu de iptables-blocktype.conf
:
# Fail2Ban configuration file
#
# Author: Daniel Black
#
# This is a included configuration file and includes the defination for the blocktype
# used in all iptables based actions by default.
#
# The user can override the default in iptables-blocktype.local
[INCLUDES]
after = iptables-blocktype.local
[Init]
# Option: blocktype
# Note: This is what the action does with rules. This can be any jump target
# as per the iptables man page (section 8). Common values are DROP
# REJECT, REJECT --reject-with icmp-port-unreachable
# Values: STRING
blocktype = REJECT --reject-with icmp-port-unreachable
Comme nous pouvons le constater, nous avons ici un formidable jeu de piste.
En résumé
Une prison définit principalement :
- un fichier de logs à observer ;
- un filtre pour en extraire les signes d'une attaque ;
- une action à mener en fonction du constat d'attaque, action qui tient compte du nombre se signes trouvés dans un e fenêtre temporelle donnée, du temps de bannissement infligé et du type d'alerte à envoyer au responsable, typiquement un e-mail, sans oublier la consignation dans un fichier de logs
/var/log/fail2ban.log
.
Cette version de fail2ban
propose même une prison pour récidivistes, qui fonctionne comme les autres, mais en consultant le le fichier de logs de fail2ban
lui-même.
Si l'on se contente de la plupart des valeurs par défaut, en agissant essentiellement sur les durées de bannissement et le nombre de tentatives avant action défensive, fail2ban
n'est pas trop compliqué à mettre en œuvre.
Si l'on souhaite modifier plus en profondeur le comportement, il devient nécessaire d'étudier correctement le fonctionnement de l'outil, et cette étude n'est pas triviale.
Enfin, n'oublions pas que cet outil fonctionne en analysant des logs, si bien qu'il réagit avec un temps de retard, surtout si le service de logs (rsyslog en ce qui nous concerne) « bufferise » les messages. Il faut donc tenir compte de cette limitation et surtout être sûr du bon fonctionnement de son système de logs.
Exercice pratique
En fonction de ce qui a été vu, éventuellement en créant de nouveaux fichiers dans action.d
si besoin est, trouvez une solution pour bannir les attaquants ssh
en les « tarpitant » plutôt qu'en leur envoyant simplement un icmp-port-unreachable
.
Souvenez-vous que la cible TRAPIT –tarpit
ne peut être visée que par TCP
alors que REJECT –reject-with icmp-port-unreachable
peut s'appliquer à tout protocole.
Considérez que d'autres protocoles peuvent ou doivent être protégés selon la méthode choisie par défaut, ou une autre méthode originale.
Jetez un œil (au figuré n'est-ce pas) sur le manuel des xtables-addons
, particulièrement sur la cible CHAOS –delude
dont l'effet peut s'avérer particulièrement déroutant pour l'attaquant.