Depuis plusieurs années j'utilise un routeur Netgear R8000 avec le firmware FreshTomato, un fork du défunt TomatoUSB. Et j'ai eu envie de bloquer les scans de sites publiques comme Shodan ou Censys.
Mais soyons clair : cela n'augmentera la sécurité et ne diminuera pas le risque de scans/attaques depuis l'extérieur (ce que pourrait faire un fail2ban).
Cela évite quelques scripts kiddies en cas de grosses vulnérabilités, et puis c'était un petit challenge technique.
Fonctionnement
Nous allons injecter des règles dans iptables pour bloquer des listes d'IP v4 publiques correspondant à celles des scanners comme Shodan ou Censys.
Pour rappel, iptables permet de configurer des règles côté utilisateur afin qu'elles soient injectées dans netfilter côté noyau Linux.
Ce tutoriel fonctionne avec FreshTomato et potentiellement tous les forks qui s'en rapprochent.
ipset est une extension d'iptables qui permet de gérer des ensembles d’adresses IP, contrairement aux chaînes iptables classiques. IPset facilite la création de listes d'adresses autorisées et/ou bloquées.
L'idée est donc de stocker une liste d'adresses IP dans un fichier texte pour ensuite le parser et injecter ces IP pour les bloquer depuis internet (chaine INPUT) :
# shodan: 64.226.86.0/24 64.227.90.0/24 64.227.107.0/24 # censys: 162.142.125.0/24 167.94.138.0/24 # etc...
La génération de ce fichier sera abordée dans un autre article afin de ne pas surcharger celui-ci.
En attendant voici la liste contenant les IP/réseaux de shodan et censys ici :
➡️télécharger le fichier blocklist shodan/censys
Merci Arthur pour les listes 😉
Pré-requis
Vous aurez besoin d'un espace de stockage persistant : clé USB ou partition /jffs. Dans mon cas j'utilise une clé USB.
Nous devons activer des modules de filtrage spécifiques dans le noyau, au démarrage du routeur.
Depuis un terminal SSH, saisissez :
modprobe -a ip_set xt_set ip_set_hash_ip ip_set_hash_net ipset create shodan hash:net
La 1ʳᵉ ligne active les modules de filtrage par IP et par réseau (subnet) dans le noyau Linux du routeur FreshTomato.
La 2ᵉ ligne créé un ipset nommé "shodan" que nous alimenterons ensuite par un script à partir de la blocklist fournie avant les pré-requis.
Important : si vous perdez la connexion SSH c'est qu'un des modules est manquant (voir section "bugs possibles").
Pour rendre ce paramétrage persistant, allez dans Administration > Scripts puis coller les 2 lignes que vous avez saisies manuellement :
Comment manipuler un ipset ?
Voici quelques commandes de base pour comprendre ce que fera le script et éventuellement le déboguer.
Affiche le contenu de l'ipset "shodan" :
ipset list shodan
Vider le contenu de l'ipset "shodan" (sans le supprimer) :
ipset flush shodan
Supprimer l'ipset "shodan" (ne doit plus être utilisé par netfilter pour que cela fonctionne) :
ipset destroy shodan
Lier l'ipset à une chaine iptables (INPUT)
Pour bloquer tout ce qui correspond à l'ipset "shodan" dans iptables (chaine INPUT) :
iptables -I INPUT -m set --match-set shodan src -j DROP
L'option "-I" permet d'insérer la règle en début de chaine en décalant les règles existantes vers le bas.
Pourquoi? parce que iptables fonctionne dans cet ordre : la première règle évaluée et qui correspond s'applique au détriment de la suite. Au contraire si nous voulions ajouter la règle en fin de chaine c'est l'option "-A" que nous aurions du utiliser, comme "append".
Ajout du script d'init
Lorsque le service "firewall" démarre il va lire la configuration web, nous devons donc préciser l'utilisation de l'ipset "shodan" en blocage.
Allez dans Administration > Scripts > Firewall puis coller :
iptables -I INPUT -m set --match-set shodan src -j DROP
Sauvegardez en cliquant sur le bouton "save".
Pourquoi ne pas appeler ici le script inject_blocklist_to_iptables.sh ? On s'affranchit de potentielles problématiques de montage/corruption de la clé USB et on évite un souci un crash au démarrage du routeur. On appellera ce script dans la partie "Wan Up".
Peupler l'ipset avec adresses IP et sous-réseaux
Afin de comprendre ce que l'on fait, voici un exemple.
Imaginons que nous voulons ajouter l'IP 12.34.56.78 et le réseau 137.184.13.0/24 dans l'ipset "shodan" pour les bloquer.
Nous saisissons en SSH :
ipset -! add shodan "12.34.56.78" ipset -! add shodan "137.184.13.0/24"
La syntaxe "-!" correspond à l'option "-exist", ce qui évite d'avoir une erreur si l'adresse/réseau ajouté est déjà présent dans l'ipset concerné.
Il est aussi possible de préciser une ip au format CIDR (ex: 12.34.56.78/32) :
ipset -! add shodan "12.34.56.78/32"
La prise en compte est immédiate.
Maintenant que vous avez compris le principe nous allons utiliser le script que j'ai écrit, qui va lire les IP/réseaux à bloquer puis injecter le tout dans iptables.
Le script
➡️télécharger inject_blocklist_to_iptables.sh
Lancez-le d'abord à la main (adaptez le chemin suivant l'emplacement sur la clé USB/JFFS) :
/tmp/mnt/CLEUSB/scripts/iptables/block_shodan_censys/inject_blocklist_to_iptables.sh
Le script va injecter la liste des IP à bloquer dans iptables, tout seul comme un grand. Si tout fonctionne nous allons pouvoir le rendre persistant :
Allez dans Administration > Scripts > Firewall :
Dans mon cas avec mon chemin cela donne :
/bin/sh /tmp/mnt/CLEUSB/scripts/iptables/block_shodan_censys/inject_blocklist_to_iptables.sh
Sauvegardez en cliquant sur le bouton "save".
A chaque fois que votre routeur va (re)trouver l'accès à internet le script s'exécutera. Si ce n'est pas suffisant pour vous ajouter une exécution au moment de votre choix dans le planificateur via Administration > Scheduler.
Toutes les 24h semble être une bonne idée, tout cela dépend si votre fichier de liste d'IP est régulièrement mis à jour ou non.
Voir les règles iptables actives
Pour afficher toutes les règles de la chaine INPUT :
iptables -S INPUT
Pour afficher toutes les règles avec le nombre de paquets qui ont matché sur chaque règle :
iptables --list --numeric --verbose --line-numbers
Ou la version courte :
iptables -L -n -v --line-numbers
Bugs possibles
S'il vous manque un des modules noyau j'ai constaté que le routeur part en utilisation CPU proche de 100% et coupe la connexion SSH ouverte dans laquelle vous aurez saisi la commande pour créer l'ipset. C'est pourquoi je vous conseille d'activer les modules à la main en SSH avant de les rendre persistant par script dans l'interface web (pour éviter le plantage du routeur au démarrage...).
Pour redémarrer le service firewall :
service firewall restart
⚠️ Attention : cette commande va recharger uniquement la configuration depuis votre interface web tomato ainsi que les scripts. Tout ce que vous aurez saisi en SSH devra être de nouveau saisi pour que ce soit actif.
ℹ️ N'hésitez pas à jeter un œil côté logs (Status > Logs) car le script écrira ses erreurs et informations si vous avez besoin de vérifier des choses. Sous condition que vos logs ne tournent pas trop vite, ou bien que vous ayez activer la journalisation sur une clé USB.
Conclusion
Voilà un tutoriel qui pourra servir de base pour d'autres usages. Je n'ai pas parlé d'IPv6 mais c'est à tout à fait possible moyennant un peu d'adaptation.
J'ai pris le temps d'expliquer comment tout ça fonctionne, en plus de la fourniture du script. N'hésitez pas à me faire un retour ou poser vos questions si vous en avez.
J'ai regroupé shodan et censys dans le même ipset, parce que c'est plus simple ainsi. Mais vous pouvez faire autant d'ipset qu'il vous en plaira, pensez à dupliquer la dernière ligne du script avec votre fichier *.list
Gardez en tête que si vous déclarez des subnet entiers dans un ipset de type "hash:ip" iptables va convertir les subnets en IP donc ça se remplira très vite. C'est la raison pour laquelle je suis parti sur les subnets.
Enfin, par défaut la limite est fixée à 65536 lignes dans chaque ipset. Pour augmenter cette valeur il faudra spécifier l'option maxelem. Mais attention à ne pas surcharger votre routeur !
Sources utiles :
- Script d'inspiration (github)
- manuels : ipset (voir "inet6" pour ipv6)
- How to block Shodan scanners (ipfire)
- Utiliser ipset sur Linux (malekal)
- iptables / netfilter (youtube)
- Bloquer des pays entiers : github, reddit
- Adaptation ipv6 et nombre d'éléments maximum (65536)
- Autre exemple qui peut servir...
Auteur : Mr Xhark
Fondateur du blog et passionné par les nouvelles techno, suivez-moi sur twitter
Le premier commentaire c'est pour vous 👇