# nono : détecter les tentatives d'intrusion et sévir 2023-06-30T13:40:08Z Dans mon fichier ''todo.txt'', il y avait d'écrit : > Réécrire vilain en C Vilain, c'était un outil en python pour analyser les logs et détecter des tentatives d'intrusion pour bannir les IP correspondantes. https://framagit.org/prx/vilain Ça a vieilli, ce n'est pas si bien écrit, et ça intègre un démon alors qu'on doit pouvoir faire mieux avec moins. Alors, quand j'ai vu l'article de Solène qui présentait une solution similaire mais en awk, j'y ai vu un cadeau : https://dataswamp.org/~solene/2023-06-22-opensmtpd-block-attempts.html Mais oui! awk est parfait pour ce genre de tâches! J'ai eu l'idée d'utiliser ''tail -f'' pour monitorer en continu les logs. En cas de rotation, tail sait se débrouiller, ce qui permet d'avoir un démon à moindre cout :) Solène m'a donné envie de m'y mettre, et en quelques heures, j'avais un nouvel outil qui faisait comme vilain, mais en mieux, car en awk. Ça s'appelle nono, et c'est par ici : https://si3t.ch/w/doku.php?id=code:nono.awk Je pourrais y ajouter un démon... Pour l'instant, je le laisse dans tmux pour voir ce que ça donne. Et semble-t-il, ça tourne bien : ``` Jun 30 10:26:55 ledzep nono: 65.49.1.48 is naughty and is now banned because: ssh wrong pw or invalid user Jun 30 12:47:13 ledzep nono: 178.151.169.14 is naughty and is now banned because: ssh wrong pw or invalid user Jun 30 13:33:45 ledzep nono: 118.185.157.225 is naughty and is now banned because: ssh wrong pw or invalid user Jun 30 13:33:57 ledzep nono: 122.0.26.154 is naughty and is now banned because: ssh wrong pw or invalid user ``` Le code se présente ainsi. On commence par vérifier si l'utilisateur a défini les options, sinon on attribue des valeurs par défaut. La fonction ''usage()'' ne fait qu'afficher l'aide. ``` BEGIN { if ((ARGV[2] == "-h") || (ARGV[2] == "--help")) { usage() } # check for options or set defaults if ( ! TRIES ) { TRIES = 5 } if ( ! BANCMD ) { BANCMD = "pfctl -T add -t bot" } if ( ! KILLSTATE ) { KILLSTATE = "pfctl -k" } if ( ! IGNORE ) { IGNORE = "/etc/nono.ignore" } } ``` Ensuite, on a des blocs correspondant aux lignes des logs pouvant indiquer un défaut. Par exemple, pour les tentatives de connexion ssh: ``` / sshd.* Failed password | sshd.* Invalid user / { match($0, "from ([0-9\.:abcdef]*)") ``` Dans l'exemple ci-dessus, on recherche une ip/ipv6 dans la ligne détectée. Si une ip est obtenue, on appelle la fonction 'ban' qui enregistre dans un tableau si l'ip a déjà été vue. Si cela dépasse le nombre maximum de tentatives, elle est bannie : ``` function ban(seen, ip, reason) { seen[ip]++ if(seen[ip] >= tries) { if (isignored(ip) == 0) { system(sprintf("logger -t \"nono\" \"%s is naughty and is now banned because: %s\"", ip, reason)) system(sprintf("%s %s", BANCMD, ip)) system(sprintf("%s %s", KILLSTATE, ip)) } seen[ip] = 0 # reset } } ``` Un tableau était tout à fait adapté pour ça. Ici, j'utilise la fonction ''system'' pour appeler une commande qui enregistre l'activité de nono et bannit l'ip. Utiliser xargs comme le fait Solène semble tout aussi intéressant, ici je me suis juste restreint à awk. On voit qu'avant de bannir l'ip, un appel à ''isignored'' est réalisé pour éviter de s'auto-bannir. Cette fonction va parcourir les lignes d'un fichier à la recherche de l'ip. Merci ''getline'': ``` function isignored(ip) { ret = 0 while ((getline current_ip < IGNORE) == 1 ) { if (ip == current_ip ) { ret = 1 break } } close(IGNORE) return ret } ``` Et voilà, c'est à peu près tout :) Merci Solène ! --- Une réaction? Envoyez votre commentaire par mail (anonyme): mailto:bla@bla.si3t.ch?subject=nono Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages: https://si3t.ch/log/_commentaires_.txt