Comment protéger SSH avec Fail2ban des attaques DoS / Bruteforce

SSH est assez sécurisé, surtout si vous prenez des précautions raisonnables, telles que nécessitant une authentification basée sur une paire de clé. Cependant, il y a encore beaucoup de bots sur internet qui essaient de trouver des hôtes vulnérables en essayant de vous connecter avec des noms d'utilisateur et des mots de passe faibles. Bien que cela soit improbable, ils réussissent, ils consomment toujours votre bande passante et généreront des quantités massives de logs.

Une approche pour minimiser le nombre de tentatives de connexion par bruteforce est de modifier le port par défaut de l'écoute de SSH.

Un meilleur moyen de résoudre le problème à la main consiste à utiliser un outil qui bloquera l'attaquant d'accéder au serveur SSH. L'un de ces outils largement adoptés est Fail2Ban. En analysant les journaux Linux, Fail2Ban découvre des tentatives d'authentification échouées répétées et définit automatiquement les règles de pare-feu (iptables, ufw) pour bloquer le trafic provenant de l'adresse IP de l'attaquant.
De ce fait, Fail2ban peut aider à bloquer les attaques DDoS visant le service SSH.

Ce tutoriel vous guide pour mettre en place Fail2ban afin de protéger votre serveur SSH.

Comment protéger SSH avec Fail2ban

Principe de fonctionnement de Fail2ban

Les pirates mettent en place des machines qui vont effectuer des scans afin de tenter de trouver un utilisateur avec un mot de passe faible d'un compte.
Cela permet de compromettre le serveur.
Notamment certains groupes de ransomwares ont mis en place des infrastructures pour viser les services SSH, PostGres, RDP et SAMBA et ainsi gagner un accès sur le réseau pour mener leurs opérations cybercriminels.
Parfois pire encore, le service SSH est visé par des attaques par bruteforce pour mettre hors ligne un serveur.

Ces tentatives sont enregistrées dans les journaux Linux dans /var/log/auth :

Nov 24 10:35:37 www sshd[32049]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=126.77.170.137  user=root
Nov 24 10:35:39 www sshd[32049]: Failed password for root from 126.77.170.137 port 59682 ssh2
Nov 24 10:35:40 www sshd[32049]: Received disconnect from 126.77.170.137 port 59682:11: Bye Bye [preauth]
Nov 24 10:35:40 www sshd[32049]: Disconnected from authenticating user root 126.77.170.137 port 59682 [preauth]
Nov 24 10:35:47 www sshd[32053]: Invalid user baikal from 176.111.173.237 port 53456
Nov 24 10:35:47 www sshd[32053]: pam_unix(sshd:auth): check pass; user unknown
Nov 24 10:35:47 www sshd[32053]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=176.111.173.237
Nov 24 10:35:48 www sudo: pam_unix(sudo:session): session opened for user root(uid=0) by malekalmorte(uid=0)
Nov 24 10:35:48 www sudo: pam_unix(sudo:session): session closed for user root
Nov 24 10:35:49 www sshd[32053]: Failed password for invalid user baikal from 176.111.173.237 port 53456 ssh2
Nov 24 10:35:50 www sshd[32053]: Received disconnect from 176.111.173.237 port 53456:11: Bye Bye [preauth]
Nov 24 10:35:50 www sshd[32053]: Disconnected from invalid user baikal 176.111.173.237 port 53456 [preauth]
Attaque Bruteforce sur le service SSH

Fail2ban surveille ces journaux pour créer automatiquement une règle iptables, ufw ou autres firewall afin d'ajouter la machine en liste noire et la bloquer totalement.
Ainsi, fail2ban protège contre les tentatives répétées d'authentification sur le service soit par des attaques par bruteforce ou DoS.

Le nombre de tentatives de connexions à partir du moment où Fail2ban déclenche une action est paramétrable.
L'action l'est aussi, on peut créer une règle iptables, ufw ou même ipset.

Comment installer Fail2ban

Sur Ubuntu, Debian, Mint ...

Pour installer fail2ban sur des distributions Linux de type Debian comme Ubuntu, Mint, on utilise APT :

sudo apt install fail2ban

Sur CentOS, Fedora, Redhat

Pour installer fail2ban sur des distributions Linux à base Redhat comme Fedora ou CentOS :

dnf install fail2ban

Comment protéger SSH avec Fail2ban des attaques DoS / Bruteforce

Vérifier que Fail2ban fonctionne et est actif

Vérifiez que le service Fail2ban est fonctionne avec systemctl :

sudo systemctl status fail2ban
Afficher les informations du service fail2ban avec systemctl

Puis vérifiez que les règles iptables sont bien créées :

sudo iptables -L -n -v

Dans la chaîne INPUT, on trouve une règle iptables f2b-sshd visant le port 22 (dports 22).
Enfin une chaîne f2b-sshd est aussi créées.

Chain INPUT (policy DROP 1 packets, 52 bytes)
 pkts bytes target     prot opt in     out     source               destination
92820 5199K f2b-sshd   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 22

Chain f2b-sshd (1 references)
 pkts bytes target     prot opt in     out     source               destination
90937 5058K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Pour vérifier que le jail SSH est actif :

sudo fail2ban-client status

Status
|- Number of jail:      4
`- Jail list:   ban1day, nginx-limit-req, ssh-reflection, sshd

Le nombre de prisons (jail) s'affichent avec la liste. Ici nous en avons 4, il faut bien vérifier que sshd est présent.

Afficher le statut des jails avec fail2ban-client

Enfin pour obtenir des statistiques sur fail2ban SSH :

sudo fail2ban-client status sshd

Status for the jail: sshd
|- Filter
|  |- Currently failed: 8
|  |- Total failed:     2134
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     223
   `- Banned IP list:

Par exemple, ici nous avons eu 2134 tentatives de connexion au service SSH et 223 adresses IP ont été bannies depuis le lancement de fail2ban.

Afficher la configuration jail ssh avec fail2ban-client

Configurer fail2ban

La configuration par défaut devrait être suffisante dans la plupart des cas. Cependant, il est bon de comprendre quelles sont les valeurs par défaut et comment vous pouvez les adapter à vos besoins.

Avec la configuration standard, Fail2Ban protégera SSH Server et bloquera la partie malveillante pendant 10 minutes après 5 tentatives de connexion ayant échoué dans les 10 minutes.
Le fichier de configuration par défaut peut être trouvé dans /etc/fail2ban/jail.conf. Le fichier est bien documenté et surtout auto-explicite.
N'oubliez pas que vous ne devez apporter aucune modification à ce fichier car il pourrait être écrasé pendant la mise à niveau de Fail2Ban.

On conseille de le copier vers /etc/fail2ban/jail.local afin d'apporter les modifications souhaitée.
Cela afin de ne pas perdre sa configuration lors du mise à jour du système ou du paquet.

cp /etc/fail2ban/jail.{conf,local}
Notez que sur Debian, vous pouvez aussi créer le fichier de configuration dans /etc/fail2ban/jail.d/sshd

La configuration générale de fail2ban se fait dans /etc/fail2ban/jail.local se trouve au début du fichier :

# "bantime" is the number of seconds that a host is banned.
bantime  = 10m

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 10m

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
maxmatches = %(maxretry)s
  • bantime : le délai où une adresse IP est bannie
  • findtime : le délai pour remonter dans les journaux
  • maxretry : le nombre de tentatives au delà duquel le nom d'hôte est bannie

Si vous changez ces éléments, cela affectera tous les services réseau protégés par Fail2ban.
Ainsi pour personnaliser la configuration SSH, modifiez les éléments dans la section [sshd].
Par exemple ici j'ajoute bantime = 60h pour bannir une adresse IP pendant 60 heures.

[sshd]
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
bantime = 60h
maxretry = 3

En rendant fail2ban plus sensible, le nombre de hosts blacklistés augmente mais cela reste tout de même assez faible.

Nombre de hosts blacklistés par fail2ban pour protéger le port SSH
Nombre de hosts blacklistés par fail2ban pour protéger le port SSH

Ensuite, vous pouvez mettre des adresses IP ou blocs d'IP en liste blanche avec ignoreip :

ignoreip = 127.0.0.1/8 10.128.31.48

Il n'y a pas besoin de relancer le service fail2ban.
Pour vérifier la prise en compte de la configuration :

fail2ban-client -d|grep "'sshd', "

Notamment vérifiez la prise en compte de la configuration maxmatches, findtime, bantime.

['set', 'sshd', 'maxretry', 3]
['set', 'sshd', 'findtime', '10m']
['set', 'sshd', 'bantime', '60h']

La configuration du jail est aussi indiquée dans /var/log/fail2ban.log au moment de relancer le service :

systemctl reload fail2ban

Puis dans /var/log/fail2ban.log :

2021-11-24 11:21:47,022 fail2ban.server         [23542]: INFO    Reload jail 'sshd'
2021-11-24 11:21:47,023 fail2ban.filter         [23542]: INFO      maxLines: 1
2021-11-24 11:21:47,024 fail2ban.filter         [23542]: INFO      maxRetry: 5
2021-11-24 11:21:47,024 fail2ban.filter         [23542]: INFO      findtime: 600
2021-11-24 11:21:47,025 fail2ban.actions        [23542]: INFO      banTime: 216000
2021-11-24 11:21:47,025 fail2ban.filter         [23542]: INFO      encoding: UTF-8

Changer le mode normal, aggressive, ddos, extra

Dans la configuration SSH de fail2ban, on trouve plusieurs modes : mode normal, aggressive, ddos, extra.
Ces derniers permettent de prendre en compte des lignes supplémentaires dans les logs Linux afin de rendre la détection plus sensibles.
Par défaut, fail2ban est configuré avec le mode normal.

Le mode extra prend en compte les lignes avec les erreurs de négociation :

Nov 24 11:06:47 www sshd[37950]: Unable to negotiate with 23.183.82.180 port 42278: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1 [preauth]

Le mode DDoS (et aggressive) étend les reconnaissances de fail2ban avec les lignes 'Connection closed by ... [preauth]', ce qui permet de prendre en compte les échecs de la connexion de clôture dans le stade de preauth.

mode `ddos` (and `aggressive`) extended to catch `Connection closed by ... [preauth]`, so in DDOS mode
    it counts failure on closing connection within preauth-stage (gh-2085);

Il s'agit des tentatives suivants :

Aug 29 13:55:05 xxx sshd[794]: Connection closed by 92.222.1.40 port 58920 [preauth]
Aug 29 13:55:07 xxx sshd[827]: Connection closed by 112.65.170.186 port 49833 [preauth]
Aug 29 13:58:53 xxx sshd[3775]: Connection closed by 112.65.170.186 port 38428 [preauth]
Aug 29 14:00:06 xxx sshd[4714]: Connection closed by 92.222.1.40 port 36348 [preauth]
Aug 29 14:02:40 xxx sshd[6669]: Connection closed by 112.65.170.186 port 55252 [preauth]

Enfin Le mode aggressive reprend tous les modes soit donc normal + ddos + extra.

Les règles sont indiquées dans le fichier /etc/fail2ban/filter.d/sshd.conf.

Pour changer de mode, indiquez celui-ci dans la section ssh du fichier /etc/fail2ban/jail.conf

[sshd]
mode=ddos

Utiliser Fail2ban avec ipset ou ufw

UFW (Uncomplicated Firewall) est un autre outil de gestion du pare-feu qui est récemment devenu une norme sur différentes distributions Linux.

Avec la configuration par défaut, Fail2Ban utilise les IPTABLES pour bloquer le trafic; Cependant, il est également possible de configurer fail2ban pour utiliser UFW afin de gérer les règles.
Il nécessite d'ajouter une entrée banaction dans /etc/fail2ban/jail.local config.

Il peut être défini sur le plan global (pour toutes les prisons) dans la section par défaut:

[DEFAULT]
action=ufw

Ou dans la section sshd pour ne modifier que celui-ci :

[sshd]
action=ufw

De la même manière, vous pouvez utiliser le action ipset :

[sshd]
action    = iptables-ipset-proto4[name=blacklist, port="22", protocol=tcp]

Cela créé un jeu ipset f2b-blacklist que l'on peut visualiser à l'aide de la commande suivante :

ipset list f2b-blacklist
Blacklist f2b-blacklist par fail2ban sur ipset pour protéger le service SSH

Plus d'informations :