Bannir les tentatives d'accès ssh

Pour bloquer des tentatives de connexion ssh, c’est assez simple et ne demande pas d’utiliser iptables. On peut utiliser iptables (j’ai une version iptables en stock) mais ce n’est pas indispensable. On utilisera ici plutôt le tcp wrapper tcpd et ses fichiers /etc/hosts.deny et hosts.allow. Le script analysera la fréquence des messages d’échec de connexion que sshd envoie dans /var/log/auth.log dans une configuration standard. Si le nombre de ces échecs dépasse un certain seuil, l’ip est bloquée.

Mais attention! Si vous installez ce script sur un serveur distant gardez toujours une connexion ouverte et faites vos essais sur une autre session ssh sinon vous risquez de vous isoler complètement de votre machine distante. Si, si ça arrive! :whistle:

Vous êtes prévenus!
[ul]

[li]Pour éviter cette mésaventure commencez par mettre une ip de confiance dans /etc/hosts.allow comme ceci:

sshd: 123.123.123.123

[/li]
[li]Ensuite ajoutez cette ligne dans /etc/hosts.deny (ou tout autre chemin/fichier de votre choix à préciser dans le script: variable $DENY_FILE)

sshd: /tmp/ipban-ssh

[/li]
[li]Vous pouvez également vous créer un fichier de blacklist perso. Une ip par ligne.

[/li]
[li]Si vous voulez débloquer une ip de confiance qui se retrouverait bloquée par accident, il ne suffit pas de la supprimer du fichier ipban-ssh car, si les conditions de bannissement existent toujours, elle se rajoutera automatiquement à la prochaine exécution du script. Il faut plutôt l’ajouter dans /etc/hosts.allow. Principe de la whitelist.

[/li]
[li]Utilisation, par exemple pour bannir une ip qui aurait fait plus de 20 tentatives par minute

$ ipban4ssh -m 20

[/li]
[li]Ou plus de 50 tentatives par heure

$ ipban4ssh -h 50

[/li]
[li]exécutez ce script par cron à la fréquence de votre choix.

[/li]
[li]Ce script ne marchera que pour le format de log sshd standard Debian comme par exemple celui-ci:

May 29 15:03:22 ursule sshd[2590]: Invalid user jjj from 192.168.0.158 May 29 15:03:22 ursule sshd[2590]: Failed none for invalid user jjj from 192.168.0.150 port 50725 ssh2 May 29 15:03:23 ursule sshd[2590]: Failed password for invalid user jjj from 192.168.0.150 port 50725 ssh2 May 29 15:03:24 ursule sshd[2592]: Invalid user jjj from 192.168.0.150
Si ce n’est pas le cas il faudra modifier le script (une seule ligne à changer) ou votre format de log.[/li][/ul]

[code]#!/bin/sh

Utilisation:

$ ipban -m 15

extraction des IP ayant tenté plus de 15 connexions par minute

$ ipban -h 5

extraction des IP ayant tenté plus de 5 connexions par heure

dans /etc/hosts.deny ajouter

sshd: /tmp/ipban-ssh # voir fichier $DENY_FILE

IMPORTANT: adresse ip de secours

dans /etc/hosts.allow ajouter

sshd: <ip de secours toujours autorisée>

test des options

if [ $# -lt 2 ]; then echo “Usage: ipban -m 15 ou ipban -h 5”; exit 1; fi
if [ $1 != “-m” ] && [ $1 != “-h” ]; then echo “Usage: ipban -m 15 ou ipban -h 5”; exit 1; fi
if [ $2 -le 0 ]; then echo “Vous devez donner un seuil de tentatives par min. ou par heure.”; exit 1; fi

commandes

awk=’/usr/bin/awk’
awk=’/usr/bin/mawk’

Paramètres config

LOG_FILE=’/var/log/auth.log’
DENY_FILE=’/tmp/ipban-ssh’
BLACKLIST_FILE=‘blacklistPerso’

Initialisation variables (mise au format syslog RFC3164 de la date du jour)

export LC_ALL=C
DTE_DAY=$(date +’%d’)
DTE_TODAY=$(printf “%s %2s” $(date +’%b’) ${DTE_DAY#0})
[ $1 = “-m” ] && SUBSTR=5 || SUBSTR=2

calcul de la fréquence de connexions par minute et stockage dans le fichier $DENY_FILE

printf “# fichier des ip ayant tenté plus de %s connexions ssh - %s\n” $2 “$(date)” > “$DENY_FILE”
$awk ‘/^’"$DTE_TODAY"’.+sshd.+(Invalid user|Failed password)/ {
# extraction de ip
match($0, /from [0-9.]+ ?/)
split(substr($0, RSTART), arr, / /)
ip=arr[2]
# tableau associatif indice: [M D HH:MM ip] ou [M D HH ip]
tab[$1 $2 substr($3, 1, ‘$SUBSTR’) ip]++
if (tab[$1 $2 substr($3, 1, ‘$SUBSTR’) ip] >= ‘$2’){
print ip
}
}
’ “$LOG_FILE” | sort -u >> “$DENY_FILE”

ajout blacklist perso

[ -f “$BLACKLIST_FILE” ] && cat “$BLACKLIST_FILE” >> “$DENY_FILE”

affichage de contrôle

cat “$DENY_FILE”
exit 0
[/code]

edit :
03-06: Adaptation au format date de syslog (rfc 3164) et modification du filtre awk pour tenir compte des tentatives sur un nom d’utilisateur existant.

Super,
Ça m’a l’air redoutable…
Il faut quand même faire remarquer que le “dé-bannissement” se fait manuellement (ou au redémarrage de la machine par vidage de /tmp) contrairement à fail2an, enfin si j’ai bien compris.

Il doit donc facilement y avoir un moyen de lancer une tâche cron pour nettoyer les trop anciennes entrées.
Le script doit d’ailleurs pouvoir s’utiliser en renforcement de fail2ban, pour les tentatives répétées ou trop rapprochées, non ?

La liste des ip bannies est, de toutes façons, à chaque fois écrasée par les nouvelles exécutions du script. Il n’y a effectivement pas de rémanence. Si une ip mal intentionnée reste tranquille plus d’une journée (selon le logrotate de /var/auth.log) elle disparaîtra de la blacklist. Mais dès qu’elle recommence, elle y retourne!

Je précise que ceci n’a pas l’ambition de remplacer fail2ban. C’est juste un petit script léger et facile à installer pour tout qui n’a pas envie de se plonger dans l’installation de fail2ban.

Re,
J’y vois un grand intérêt concernant ipv6…
Fail2ban n’en est qu’au stade expérimental, ton script devrait s’avérer très utile… :wink:

Pour ipv6 je ne pense pas que tcpd le supporte. Si aucune version ip6 du tcp wrapper de debian ne sort, il faudra passer par iptables j’imagine…

Tu dois avoir raison, je n’avais pas cherché…
Il suffirait donc de lancer une commande avec iptables, mais se pose à nouveau le pb du “dé-bannissement”…

Du fait que le script écrase à chaque fois le fichier des punis, le bannissement n’est pas persistant. Le dé-bannissement est automatique. Si tu donnes -h 50 comme option au script, une ip faisant plus de 50 tentatives de connexion infructueuses dans l’heure courante se retrouvera dans le fichier deny. Si elle se tient tranquille dans l’heure suivante, le script ne la trouvera plus puisque l’heure courante aura changé. Elle sera donc à nouveau autorisée mais dès qu’elle recommence elle retournera en prison.

Encore un mot au sujet de l’utilité d’avoir un script léger. Je l’utilise, entre-autres, sur mes routers (OpenWRT) qui n’ont que 16 MB de ram. Difficile donc, d’y installer Phyton et fail2ban alors que toutes les commandes du script sont disponibles sur toutes les distro linux, y compris celles qui utilisent Busybox comme OpenWRT ou DD-WRT. Il faut juste adapter le script au format syslog des routers (une seule ligne à changer) et utiliser iptables plutôt que le wrapper tcpd qui n’est pas disponible sur mes OpenWRT.

Re,

Je viens de le tester, ça fonctionne parfaitement (j’ai désactivé fail2ban et autofwd… que j’avais oublié!).

Quand je parlais de “dé-bannissement” je parlais de ipv6 et iptables, pas de ton script. Mais ça ne pose pas de pb, je viens de regarder comment fonctionne autofwd, ça m’a donné la solution.

fail2ban ET autofwd. Dis-donc, c’est une véritable forteresse chez toi! As-tu aussi des oubliettes (honeypot)? :wink:

:laughing: Pas la peine…

Je cherchais une alternative à fail2ban qui ne supporte pas encore ipv6 (alors que le lancement officiel à lieu dans quelques jours… et que je l’ai activé sur mes dédiés), et j’étais tombé sur autofwd. Il était resté installé…

Merci , merci !!

Je vais tester ça ! :023

Salut !

Pour enlever les vieux IP bannis il serait peut-être aussi intéressant d’étudier ce script, voire peut-être de l’adapter pour la protection ssh (voire même peut-être pour tous types de Flood ou encore d’attaques).
A noter que le script est récent parce qu’il est régulièrement réactualisé.

Il a été conçu pour détecter et bannir les IP qui pratiquent de l’UDP Flood
Les anciennes IP sont automatiquement supprimées au bout d’un moment.
Le script nécessite entre autre tcpdump et awk.

Il est généralement utilisé avec Cron.

http://et-zone.de/downloads/?action=download&id=14

Bonsoir,

J’ai regardé en diagonale le script que tu renseignes. Contrairement à fail2ban et mon script plus haut qui, tous deux, analysent les logs, celui-ci semble utiliser une capture de tcpdump des paquets entrants. Il travaille plus près de la source en quelque sorte. Mais il ne fait aussi qu’une analyse statistique a posteriori. Tant qu’à travailler au niveau des paquets, autant utiliser directement le module recent d’iptables qui, lui, travaille à la volée.

Une ébauche à la grosse louche:

[code]# création d’une chaîne utilisateur
iptables -N logAndDrop

enregistrement des IP dans le fichier myBlacklist

iptables -A INPUT -p tcp --dport 22 -m recent --name myBlacklist --set

si une IP du fichier fait plus de 10 tentatives dans les 10 secondes --> vers la chaîne logAndDrop

iptables -A INPUT -p tcp --dport 22 -m recent --name myBlacklist --update --seconds 10 --hitcount 10 -j logAndDrop

chaîne logAndDrop qui fait ce que ça dit: LOG et ici REJECT

iptables -A logAndDrop -j LOG --log-prefix "IPT_mySSHfilter"
iptables -A logAndDrop -j REJECT
[/code]

Pour simuler une attaque vous pouvez utiliser nc, “le couteau suisse TCP/IP”:

Mais ATTENTION, ici, contrairement au wrapper qui permet de garder une connexion ssh déjà établie, iptables coupera tout trafic en cas de boulette. Mettez vos ip de secours dans une règle iptables placée au bon endroit ou ajoutez -m state --state NEW dans les règles de filtrage pour ne discriminer que les nouvelles tentatives de connexion. Ou encore, faites vos essais avec un service/port imaginaire. Par exemple faites écouter nc sur la cible sur un port de votre choix:

[code]# sur la cible
nc -l -p 123

attaque simulée sur la machine attaquante

nc ip_cible 123[/code]