Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
pratique:informatique:fail2ban [09/08/2023 09:17] – [Iptable] Zatalyz | pratique:informatique:fail2ban [23/01/2024 11:48] (Version actuelle) – [Commandes Iptables utiles] Zatalyz | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== Fail2ban et Iptables ====== | ====== Fail2ban et Iptables ====== | ||
+ | |||
+ | <WRAP center round important 100%> | ||
+ | Tout ça n'est pas encore au point. | ||
+ | |||
+ | À un moment faudra que tout ça soit revu de fond en comble... J' | ||
+ | |||
+ | En attendant, n' | ||
+ | </ | ||
+ | |||
Fail2ban logiciel me file des boutons mais je n'ai pas vraiment trouvé de remplaçant. Son principal mérite est de délayer les attaques par brute-force ; en principe notre serveur n'y est pas vulnérable, | Fail2ban logiciel me file des boutons mais je n'ai pas vraiment trouvé de remplaçant. Son principal mérite est de délayer les attaques par brute-force ; en principe notre serveur n'y est pas vulnérable, | ||
En principe aussi, il marche bien avec nftables, le nouveau pare-feu par défaut sur debian. Sauf que là aussi le principe se heurte à la pratique et j'ai le droit à des erreurs si je tente de l' | En principe aussi, il marche bien avec nftables, le nouveau pare-feu par défaut sur debian. Sauf que là aussi le principe se heurte à la pratique et j'ai le droit à des erreurs si je tente de l' | ||
- | apt install fail2ban ipset iptable iptables-persistent whois python3-systemd | + | apt install fail2ban ipset iptable |
===== Iptable ===== | ===== Iptable ===== | ||
- | Iptable-persistent permet de charger des règles au démarrage, en principe situées dans ''/ | + | *-persistent permet de charger des règles au démarrage, en principe situées dans ''/ |
+ | |||
+ | ==== Règles de base ==== | ||
Actuellement mon routeur me coince en ipv4 (''/ | Actuellement mon routeur me coince en ipv4 (''/ | ||
Ligne 71: | Ligne 82: | ||
# Usage des tables déclarées avec ipset | # Usage des tables déclarées avec ipset | ||
- | -A INPUT -m set --match-set blocklist_ip src -j DROP | + | #-A INPUT -m set --match-set blocklist_ip src -j DROP |
+ | # Ça, ça ne veut pas... | ||
+ | |||
+ | #rejeter tout le reste | ||
+ | -A INPUT -j REJECT --reject-with icmp-port-unreachable | ||
</ | </ | ||
+ | |||
+ | ==== Commandes Iptables utiles ==== | ||
+ | Lister " | ||
+ | iptables -S | ||
+ | Lister tout en format tableau verbeux, avec numéros de ligne | ||
+ | iptables -L -n -v --line-numbers | ||
+ | |||
+ | Juste dans un des tableaux (ici INPUT) | ||
+ | iptables -L INPUT --line-numbers | ||
+ | |||
+ | Sauf que ce n'est pas " | ||
+ | iptables -t nat -S | ||
+ | |||
+ | Enlever une règle d' | ||
+ | iptables -D INPUT 14 | ||
+ | |||
+ | Restaurer des règles | ||
+ | iptables-restore / | ||
+ | |||
+ | ==== Quelques explications ==== | ||
+ | === Différence entre -I et -A === | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Bref, quand on a un fichier qui charge les règles, elles sont forcément les unes après les autres, '' | ||
+ | |||
+ | === DROP ou REJECT --reject-with icmp-port-unreachable === | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | |||
+ | |||
+ | === Ordre des règles === | ||
+ | Les règles sont appliquées dans l' | ||
+ | |||
+ | Donc il faut que les commandes d' | ||
+ | - On regarde si l'un de ces logiciels dit qu'il faut bloquer l' | ||
+ | - Si oui, elle dégage | ||
+ | - Si non, on passe à la règle suivante | ||
+ | - La règle suivante étant "on accepte" | ||
+ | |||
+ | Sinon, ça serait : | ||
+ | - On accepte la connexion | ||
+ | - On regarde si fail2ban... ah ben non, forcément, ça ne marche pas, puisque la connexion est acceptée. | ||
===== Ipset ===== | ===== Ipset ===== | ||
- | Créer une entrée pour toutes les ip qui vont être renvoyées dans les limbes (adapter le nom '' | + | Créer une entrée pour toutes les ip qui vont être renvoyées dans les limbes (adapter le nom '' |
ipset create blocklist_ip hash:ip | ipset create blocklist_ip hash:ip | ||
Ligne 93: | Ligne 152: | ||
Pour enlever une des ip sur notre chaîne " | Pour enlever une des ip sur notre chaîne " | ||
ipset del blocklist_ip X.X.X.X | ipset del blocklist_ip X.X.X.X | ||
+ | |||
+ | ===== Rendre ça persistant au démarrage ===== | ||
+ | C'est netfilter qui gère ça. | ||
+ | |||
+ | S' | ||
+ | iptables -L -n -v | ||
+ | ipset list | ||
+ | systemctl status netfilter-persistent | ||
+ | |||
+ | Pour garder les ip bannies dans ipset, il faut aussi faire cette commande (à renouveler quand on ajoute des ip) : | ||
+ | ipset save | ||
+ | |||
+ | Sauver le tout : | ||
+ | netfilter-persistent save | ||
+ | |||
+ | |||
===== Fail2ban ===== | ===== Fail2ban ===== | ||
Ligne 169: | Ligne 244: | ||
</ | </ | ||
+ | Ne pas oublier de redémarrer fail2ban ensuite. | ||
+ | fail2ban-server -t | ||
+ | systemctl restart fail2ban | ||
+ | | ||
+ | ==== Commandes fail2ban utilisées régulièrement ==== | ||
+ | * Liste des jails : '' | ||
+ | * Statut d'une jail : '' | ||
+ | * Vérifier la configuration avant de relancer : '' | ||
+ | * Bannir une ip en particulier : '' | ||
+ | * Et la débannir : '' | ||
+ | ==== Faire ses propres règles Fail2ban ==== | ||
+ | Il y a quelques améliorations à faire concernant les filtres. | ||
+ | === Rendre le filtre postfix par défaut plus agressif === | ||
+ | Par défaut, la jail " | ||
- | ==== À faire ==== | + | Cherchez la ligne |
+ | mode = more | ||
+ | Et remplacer par | ||
+ | mode = aggressive | ||
+ | |||
+ | Et voilà, là, des messages comme " | ||
+ | |||
+ | === Ajouter des regex et configurer une jail " | ||
+ | |||
+ | Malgré ça, j'ai encore quelques tentatives des plus douteuses, pas toujours repérées/ | ||
+ | |||
+ | Voici un exemple de certaines lignes que je souhaite filtrer : | ||
+ | < | ||
+ | 2023-10-09T22: | ||
+ | 2023-10-08T18: | ||
+ | 2023-10-15T22: | ||
+ | 2023-07-28T09: | ||
+ | </ | ||
+ | * Envoyer une commande foireuse ? Qui fait ça en dehors de ceux qui testent les fragilités d'une installation ? | ||
+ | * Un hostname mal déclaré ? Sérieusement, | ||
+ | * Notez au passage que tout ce qui contient tiscali.it et censys est toujours bon à bloquer, c'est toujouuuurs des comportements douteux. | ||
+ | * Une commande non SMTP ? Hey, t'as cru que c' | ||
+ | |||
+ | On va donc se créer son propre filtre pour ces cochons, avec un '' | ||
+ | < | ||
+ | # Filtre perso alimenté par les détections de trucs vraiment louches. | ||
+ | [INCLUDES] | ||
+ | before = common.conf | ||
+ | [Definition] | ||
+ | failregex = ^.*\[< | ||
+ | ^.* NOQUEUE: reject: RCPT from unknown\[< | ||
+ | ^.*connect from .*censys.*\[< | ||
+ | ignoreregex = | ||
+ | [Init] | ||
+ | journalmatch = _SYSTEMD_UNIT=postfix.service | ||
+ | |||
+ | </ | ||
+ | |||
+ | Notez que chaque ligne de la partie " | ||
+ | |||
+ | Par ailleurs il faut inclure '' | ||
+ | |||
+ | On peut ensuite lancer cette commande pour voir si ça checke des correspondances : | ||
+ | sudo fail2ban-regex / | ||
+ | |||
+ | Dans le résultat, on doit avoir quelque chose comme ça : | ||
+ | < | ||
+ | |- #) [# of hits] regular expression | ||
+ | | 1) [9] ^.* improper command pipelining after CONNECT from unknown\[< | ||
+ | | 2) [1] ^.*\[< | ||
+ | | 3) [1] ^.* NOQUEUE: reject: RCPT from unknown\[< | ||
+ | | 4) [10] ^.*connect from .*censys.*\[< | ||
+ | `- | ||
+ | </ | ||
+ | Ici j'ai donc 9 correspondances sur la première expression, 1 pour chacune des deux suivants et 10 pour ce sale bot à la fin : c'est bon, ça scanne. | ||
+ | |||
+ | On ajoute ensuite la jail dans notre ''/ | ||
+ | < | ||
+ | [XX_perso_postfix] | ||
+ | #mes propres bidouilles pour virer des chieurs bien repérés | ||
+ | enabled = true | ||
+ | port = pop3, | ||
+ | filter = XX_perso_postfix | ||
+ | maxretry = 1 | ||
+ | findtime = 600 | ||
+ | bantime = 30d | ||
+ | action | ||
+ | </ | ||
+ | * Le nom de la jail doit être celui du filtre, visiblement, | ||
+ | * Il va chercher tout seul le filtre dans ''/ | ||
+ | * Les ports j'ai copié ce qui marchait avec la jail de base de postfix. | ||
+ | * 1 tentative. Une seule. Limite je me demande pourquoi je déclare le findtime. Et ensuite 30 jours de bannissement ! | ||
+ | * l' | ||
+ | |||
+ | Ensuite, on teste si on n'a pas fait de bêtise avec cette commande (ça évitera des agacements) : | ||
+ | sudo fail2ban-server -t | ||
+ | |||
+ | Tout marche ? alors, on charge : | ||
+ | sudo service fail2ban reload | ||
<WRAP center round todo 100%> | <WRAP center round todo 100%> | ||
Il faut améliorer les regexp (avec fail2ban-regex). pour virer plus large : | Il faut améliorer les regexp (avec fail2ban-regex). pour virer plus large : | ||
- toute ip qui tente de se co en ssh avec un user qui n'est pas autorisé => ban définitif | - toute ip qui tente de se co en ssh avec un user qui n'est pas autorisé => ban définitif | ||
- | - toute ip qui passe des commandes à postfix qui ne sont pas " | ||
</ | </ | ||
- | La ligne postfix que j' | ||
- | 2023-07-28T09: | ||
===== Bannir définitivement les IP harcelantes ===== | ===== Bannir définitivement les IP harcelantes ===== | ||
Ligne 197: | Ligne 361: | ||
Très beau, très simple, fonctionnel. | Très beau, très simple, fonctionnel. | ||
+ | Mais on va aller plus loin avec un petit cron qui lance de temps en temps une vérification et bannit définitivement les ip qui ont un peu trop essayé. | ||
+ | |||
+ | ==== Script de bannissement définitif ==== | ||
+ | J'ai mis ça dans / | ||
+ | |||
+ | mkdir / | ||
+ | |||
+ | <code bash banip_auto.sh> | ||
+ | #!/bin/bash | ||
+ | # Bannir automatiquement une liste d'ip qui ont abusé. | ||
+ | #fichier de log | ||
+ | folderbanip="/ | ||
+ | badiphuman=" | ||
+ | todayiptable=" | ||
+ | logban=" | ||
+ | |||
+ | ## Liste les ip gênantes, d'une façon lisible pour un humain | ||
+ | # awk ' | ||
+ | cat / | ||
+ | # sauvegarde les règles iptables et ipset actuelles pour comparer | ||
+ | iptables -L -n -v > $todayiptable | ||
+ | ipset list >> $todayiptable | ||
+ | |||
+ | # On alimente le fichier de log | ||
+ | echo "#####" | ||
+ | date >> $logban | ||
+ | ## Si l'ip est revenu plus d'un certain nombre de fois, alors on la sélectionne pour un ban définitif | ||
+ | # lire fichier $badiphuman | ||
+ | cat $badiphuman | while IFS= read -r line; do | ||
+ | tableau=(${line// | ||
+ | number=$(echo $tableau | cut -d ',' | ||
+ | ip=$(echo $tableau | cut -d ',' | ||
+ | #Si l'ip apparait 2 fois ou plus, on la bannit, sinon elle a sa chance | ||
+ | if (($number >= 2)) | ||
+ | then | ||
+ | # on va tester si on a déjà la règle | ||
+ | if grep -q " | ||
+ | then | ||
+ | echo "IP address already blocked, skipping" | ||
+ | else | ||
+ | ipset add blocklist_ip $ip | ||
+ | echo " | ||
+ | fi | ||
+ | else | ||
+ | echo "$ip not blocking for the moment, only $number try" >> $logban | ||
+ | fi | ||
+ | done | ||
+ | |||
+ | #Sauver les modifs | ||
+ | ipset save | ||
+ | netfilter-persistent save | ||
+ | # | ||
+ | |||
+ | </ | ||
+ | |||
+ | Et maintenant un cron, une fois par jour, pour s' | ||
+ | crontab -e | ||
+ | 30 0 * * * / | ||
+ | |||
+ | ===== Bannir des plages d'ip ===== | ||
+ | Parfois des comportements malveillants viennent d'une plage d'ip et pas seulement d'une ip seule. | ||
+ | |||
+ | Il faut des alertes pour les repérer (ou si y'a moyen d' | ||
+ | |||
+ | La notation d'une plage d'ip est de la forme x.x.x.0/24. Enfin, les chiffres au bout varient parfois... Comment être sûr de son coup ? | ||
+ | |||
+ | Installer '' | ||
+ | |||
+ | < | ||
+ | Address: | ||
+ | Netmask: | ||
+ | Wildcard: | ||
+ | => | ||
+ | Network: | ||
+ | HostMin: | ||
+ | HostMax: | ||
+ | Broadcast: 87.120.84.255 | ||
+ | Hosts/Net: 254 Class A | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | < | ||
+ | % ipcalc 87.120.84.0/ | ||
+ | Address: | ||
+ | Netmask: | ||
+ | Wildcard: | ||
+ | => | ||
+ | Network: | ||
+ | HostMin: | ||
+ | HostMax: | ||
+ | Broadcast: 87.120.84.255 | ||
+ | Hosts/Net: 254 Class A</ | ||
+ | |||
+ | Ici '' | ||
+ | |||
+ | ipset add blocklist_ip 87.120.84.0/ | ||
+ | |||
+ | et '' | ||
+ | |||
+ | ===== D'où viennent les attaques ? ===== | ||
+ | Là c'est de la curiosité car je ne pense pas que je puisse y faire grand chose. Mais, quand même, ça permet de voir la pertinence (ou pas) de bloquer un pays. | ||
+ | |||
+ | En premier, récupérer les logs montrant une " | ||
+ | grep " | ||
+ | |||
+ | Ensuite je me suis envoyée ce fichier via [[pratique: | ||
+ | |||
+ | Et après, j'ai mouliné ce fichier appelé " | ||
+ | < | ||
+ | # Savoir d'où vienne les méchantes ip | ||
+ | cat badip.txt | while IFS= read -r line; do | ||
+ | tableau=(${line// | ||
+ | geo=$(geoiplookup $tableau) | ||
+ | echo $geo >> country.txt | ||
+ | cat country.txt | sort|uniq -c | sort > finalbadip.txt | ||
+ | done | ||
+ | </ | ||
+ | |||
+ | Ce qui donne lors de ce test, 90 tentatives d' | ||
+ | |||
+ | Si je ne me vois pas bloquer ces pays (même la Chine), je me demande s'il y a moyen de filtrer quel pays a le droit de tester certaines actions, comme se connecter à un compte mail. | ||
+ | |||
+ | ==== Une alternative via systemd ==== | ||
+ | Pour les IPs qui ont le plus chercher à se connecter au serveur mail sans succès, pour une journée donnée : | ||
+ | journalctl --since=2023-10-06 --until=2023-10-07 --grep=' | ||
- | Ça serait pas mal qu'un petit cron lance de temps en temps une vérification et bannisse définitivement les ip qui ont un peu trop essayé. | + | Et juste pour le jour même : |
+ | journalctl --since=today --grep='SASL LOGIN authentication failed' | ||
Ligne 211: | Ligne 502: | ||
* https:// | * https:// | ||
* https:// | * https:// | ||
+ | * https:// | ||
+ | * http:// | ||