Un attaquant peut essayer en « brute force » toutes les combinaisons possibles pour trouver le mot de passe d’un compte utilisateur sur un service. Pour le détecter, il faut qu'une journalisation permette d'identifier un échec de connexion.
Le serveur Apache ou le code ne permettent pas de détecter cela. Il faut rajouter un utilitaire qui permet de détecter les comportements anormaux dans les accès aux services d’une machine : connexion trop fréquentes et en échec, connexions démultipliées dans un temps court, etc.
C’est le rôle de l’outil Fail2ban : de l’échec (Fail) à (2) un bannissement (Ban).
On doit d'abord installer fail2ban à partir des dépôts :
apt install fail2ban
On doit aussi disposer de l'outil iptables qui gèrera les règles de bannissement :
apt install iptables
Fail2ban est un outil de détection d’intrusion
Pour pouvoir détecter une intrusion, il faut donc un fichier de journalisation dans lequel des informations doivent être inscrites (échec, rejet, etc) pour que Fail2ban les repère.
Fail2ban repose sur les éléments suivants :
Pour configurer Fail2ban, la règle est de définir des fichiers spécifiques (nommés <nom>.local) dans les dossiers dédiés :
On doit surveiller les échecs de connexion sur l’application, donc via le service Apache. On va créer une configuration de base pour bloquer des tentatives de connexion infructueuses répétées sur le service apache (http/https) dans le fichier à créer :
nano /etc/fail2ban/jail.d/jail.local
Le contenu du fichier est par exemple :
[apache] ; Nom du service qu’on surveille enabled = true ; on active le service port = http,https ; ports qu’on surveille filter = apache-auth ; nom du filtre définissant le comportement intrusif logpath = /var/log/apache*/*error.log ; fichier de journalisation dans lequel on cherche le comportement intrusif maxretry = 3 ; nombre d échecs avant banissement findtime = 60 ; délai dans lequel le nombre d échec doit être détecté bantime = 10m ; durée du bannissement (10 minutes) banaction = iptables-allports #bannit l'IP sur tous les ports (il existe d'autres options moins radicales)
A ce stade, le blocage ne sera pas détecté car le filtre apache-auth ne saura pas reconnaître l'intrusion (le fonctionnement de l'application est normal, il n'y a pas d'enregistrement d'échec par défaut)
Pour comprendre le fonctionnement, on va bloquer manuellement un poste
Remplacer <ip_poste> par une IP d'un équipement du réseau, la connexion au site Web devrait indiquer « connexion échouée » alors que les autres postes ont toujours accès.
fail2ban-client set apache banip <ip_poste>
Pour débloquer
fail2ban-client set apache unbanip <ip_poste>
Cette manipulation montre le principe mais n'est pas automatisée
Pour permettre de détecter les échecs de connexion, on va générer des erreurs identifiables dans le fichier journal d’Apache pour les tentatives d’accès en échec.
Pour qu’on détecte une tentative d’intrusion, il faut que Fail2ban trouve dans un fichier journal une information qui lui permet de détecter la faille.
Par exemple, dans la page connecter.php qui vérifie l’identité de connexion, en cas d’erreur, avant le renvoi vers l’index.php, on inscrit l’erreur dans le journal d’activité :
else { error_log("echec de connexion : ".$_POST["compte"].":".$_SERVER["REMOTE_ADDR"]); header("Location: index.php"); }
On pourra observer l’inscription d'une erreur dans /var/log/apache2/error.log
tail /var/log/apache2/error.log
echec de connexion : admin:10.12.0.6, referer: http://172.20.12.102/dplace/
echec de connexion : root:10.12.0.6, referer: http://172.20.12.102/dplace/
echec de connexion : user:10.12.0.6, referer: http://172.20.12.102/dplace/
Le jail est configuré, les erreurs journalisées, mais le filtre ne prend toujours pas en compte l'information
Pour que les messages inscrits dans le journal soient pris en compte, il faut l’indiquer dans le filtre utilisé dans le jail.local.
Dans le journal, nous avons ajouté une ligne commençant par « echec » à chaque connexion erronée. Dans le jail [apache], nous avons invoqué le fichier de filtre existant /etc/fail2ban/filter.d/apache-auth.conf.
Il faut donc que celui-ci détecte nos messages.
Editez-le filtre
nano /etc/fail2ban/filter.d/apache-auth.conf
Il faut ajouter l’expression régulière qui dit que la ligne recherchée doit commencer (^) par le terme « echec » (ajout à la dernière ligne du filtre existant).
failregex = ^client (?:denied by server configuration|used wrong authentication schem> ^user (?!`)<F-USER>(?:\S*|.*?)</F-USER> (?:auth(?:oriz|entic)ation failur> ^Authorization of user <F-USER>(?:\S*|.*?)</F-USER> to access .*? failed\b ^%(auth_type)suser <F-USER>(?:\S*|.*?)</F-USER>: password mismatch\b ^%(auth_type)suser `<F-USER>(?:[^']*|.*?)</F-USER>' in realm `.+' (auth(?> ^%(auth_type)sinvalid nonce .* received - length is not\b ^%(auth_type)srealm mismatch - got `(?:[^']*|.*?)' but expected\b ^%(auth_type)sunknown algorithm `(?:[^']*|.*?)' received\b ^invalid qop `(?:[^']*|.*?)' received\b ^%(auth_type)sinvalid nonce .*? received - user attempted time travel\b ^(?:No h|H)ostname \S+ provided via SNI(?:, but no hostname provided| and> ^echec \b
Le fichier /var/log/fail2ban.log conserve la trace des détections et blocages que l'outil a mis en place.
nano /var/log/fail2ban.log
On y repère les horaires précis d'enregistrement de l'échec et l'action de banissement
2023-12-04 11:16:22,916 fail2ban.filter [2327]: INFO [apache] Found 10.12.0.6 - 2023-12-04 11:16:22 2023-12-04 11:16:24,832 fail2ban.filter [2327]: INFO [apache] Found 10.12.0.6 - 2023-12-04 11:16:24 2023-12-04 11:16:27,536 fail2ban.filter [2327]: INFO [apache] Found 10.12.0.6 - 2023-12-04 11:16:27 2023-12-04 11:16:27,725 fail2ban.actions [2327]: NOTICE [apache] Ban 10.12.0.6