NtopNG et scripts pour sécurité
NtopNG et scripts pour sécurité jppNtopNG intercepte et stocke des tas de données sur tous les événements réseau traités, l'exploitation de ces données permet, outre quelques statistiques, de repérer des événements liés à la sécurité.
Premier exemple :
Exploiter les alertes NtopNG, repérer les accès sur des ports non actifs (fermés ou filtrés).
Une version plus récente est disponible ici.
Deuxième exemple :
Repérer les scans de ports, même lents.
Exploiter les alertes NtopNG
Exploiter les alertes NtopNG jppNote : cette description "date" un peu et une version plus récente est disponible ici.
Exploiter les alertes générées par NtopNG.
Les dernières versions de NtopNG permettent d'activer un suivi d'alertes. Ces alertes sont levées pour différentes raisons :
- Accès depuis une adresse "blacklistée" par utilisation d'une liste du site Emergingthreats.
- Tentative d'accès à un port fermé ou bloqué
- Autres anomalies de comportement
Or ces alertes sont stockées dans une base de données Sqlite et donc très faciles à exploiter.
Les tables comportent le même type de renseignements que celles enregistrant les flux dans une base de données plus traditionnelle.
Les principales données sont :
- Données temporelles . timestamp, firstswitched, lastswitched
- Données sur le client. . cli_addr, cli_country (code pays), cli_port
- Données coté serveur. . srv_addr, srv_country, srv_port
- Données quantitatives. . cli2srv_bytes, srv2cli_bytes, cli2srv_packets, srv2cli_packets
- Données "techniques". . flags IP, blacklist ou pas, .....
La conservation de ces données est ajustable dans le logiciel selon différents critères dans le paramétrage de NtopNG.
Il vaut mieux limiter un peu le volume car Sqlite n'est pas adapté aux gros volumes.
On peut repérer à partir de ces données tout "hit" sur un port fermé et par exemple bloquer cette adresse avec un "ipset" bien placé dans un règle de pare-feu.
Le petit script suivant permet de repérer ces adresses IP :
select min(first_switched),cli_addr from flows_alerts where cli_addr not like '192.168.1%' and cli_addr not like '192.168.2%' and cli_addr not like '192.168.3%' and cli_addr not like '%:%' -- éliminer IPV6 and cli_addr not like '0.0.0.0' and srv_port < 32768 and first_switched > ${DATEMIN} group by cli_addr order by first_switched; |
Il faut éliminer :
- les enregistrements "anciens", la date minimum est au format "epoch", j'utilise les deux dernières heures :
DATEMIN=$(date +%s)
DATEMIN=$(expr ${DATEMIN} - 7200)
- les origines dans son propre réseau :
- ceux qui utilisent des ports "client d'un service local", ici seuls les ports inférieurs à 32768 sont pris en compte. Voir ces limites avec la commande "sysctl -a | grep local_port_range" .
Il est parfois un peu délicat de repérer les bases Sqlite car les noms de répertoires sont différents selon les machines. Pour moi le répertoire principal est /var/tmp/ntopng et les bases sont dans
13/alerts/alerts_v7.db et 15/alerts/alerts_v7.db sur une machine, sur une autre machine les répertoires sont 1 et 3 donc très différents.
Ce script est très rapide car la base Sqlite contient assez peu de rangs (moins de 5000) et peut être lancé par "cron" avec une fréquence importante pour alimenter régulièrement un "set" de blocage par IP.
Exploiter les alertes NtopNG V2
Exploiter les alertes NtopNG V2 jppNtopNG pour détecter les scans (V2).
Depuis plusieurs versions NtopNG utilise une petite base de données Sqlite pour stocker des données prises « au vol ». Au fil des versions le nombre de données, et de tables, a fortement augmenté. Certaines de ces données permettent de repérer les accès qui n’ont donné lieu à aucun transfert vers le « client » car ils tentaient un accès à un port fermé ou bloqué par le pare-feu. D'autres éléments indiquent des accès depuis des adresses "blacklistées".
A partir de ces données il est très facile, et rapide de repérer les scans de ports, même l’accès à un seul port est repérable. La base étant très légère (à la journée) les traitements sont très rapides et peuvent donc être exécutés souvent.
D’abord une mini description de la structure de ces bases de données situées dans /var/lib/ntopng dans une installation « « standard ».
L’organisation générale comporte 3 répertoires nommés : « -1 » « 0 » et « 1 ». chacun de ces répertoires contient plusieurs répertoires et nous nous intéresserons ici qu’à « alert ».
Chacun de ces répertoires contient un fichier, ici « alert_store_v11.db » dont le nom varie, malheureusement, à chaque version. Les noms des colonnes ont aussi varié au cours des versions …
En ouvrant ce répertoire dans SqliteBrowser on peu y voir la liste des tables et index.
Remarque : Il est normal que certains des 3 répertoires contiennent des tables vides … toute recherche doit donc concerner les trois répertoires.
La table qui nous intéresse ici est « flow_alerts » dont les colonnes suivantes nous intéressent :
- cli_ip et cli_port adresse et port de l’émetteur
- srv_ip et srv_port adresse et port du destinataire
On y trouve d’autres colonnes intéressantes :
- cli_name et srv_name les noms DNS
- cli_country et srv_country les codes pays
- cli_blacklisted et srv_blacklisted des indicateurs de qualité des adresses (0 ou 1) indiquant l’appartenance à une liste noire de l’adresse correspondante. Les listes noires sont maintenues à jour automatiquement et sont paramétrables dans l’interface Web de NtopNG, y compris leur fréquence de mise à jour?
Enfin les compteurs de la transmission en octets et paquets :
- cli2srv_bytes / cli2srv_pkts et srv2cli_bytes / srv2cli_pkts ce sont principalement ces compteurs qui nous intéressent car une valeur à zéro implique le refus de transmission qui marque un port fermé ou bloqué par une règle de firewall.
Certaines colonnes telles is_cli_attacker , is_srv_attacker ou is_srv_attacker , is_srv_victim précisent les choses par leur valeur 0 je fais partie des gentils, 1 je suis un méchant !
Il est donc très facile de lister par des ordres SQL simples les adresses IP dont les accès n’ont donné lieu à aucun transfert en retour.
Ensuite les adresses IP sont comparées aux « set » de "méchants" existants, si elles sont trouvées on abandonne car elles sont déjà bloquées, si elles ne sont pas trouvées elles sont stockées dans un set spécial d’attente, mais tout accès depuis une adresse présente dans ce set sera « dropé » par une règle iptables comme pour les adresses contenues dans les sets "permanents" de méchants.
Ce set est exploré toutes les heures et toute adresse présente depuis plus d’une heure est transférée dans un set permanent sauvegardé et détruite du set d’attente.
Le transfert dans un set permanent entraîne par ailleurs l’analyse des accès liés à cette adresse sur les dernières 24 heures et l’envoi d’un message au site ABUSEIPDB.COM avec la liste des ports touchés pour faire profiter les autres de la découverte d’un vilain méchant et horrible qui scanne internet, probablement pour un but pas très honnête ...
Toutes ces opérations sont assez simples à réunir et quelques scripts, un peu de bash, de SQL et de mise en forme avec awk font l’affaire.
Voir ci-dessous l'ordre SQL qui "va bien".
select min(first_seen),cli_ip from flow_alerts
where cli_ip not like '192.168.1%' and cli_ip not like '192.168.2%'
and cli_ip not like '192.168.3%' and cli_ip not like '192.168.4%'
and cli_ip not like '%:%' and cli_ip not like '0.0.0.0'
and srv_port < 32768
and tstamp > ${DATEMIN}
and srv_port not in (80,443)
and cli_port not in (liste de ports)
group by cli_ip
order by tstamp;
.quit
DATEMIN est obtenu depuis le script bash :
DATEMIN=$(date +%s)
DATEMIN=$((${DATEMIN} - 3600 )) # ou 7200 pour étendre ) 2 heures
Repérer les scans lents
Repérer les scans lents jppRepérer les scans "lents" avec NtopNG.
SI vous stockez les données de flux dans une base Mysql avec une certaine durée il est possible de repérer les scans de ports, même lents, de manière simple à l'aide d'un ordre SQL simple.
Cela permet de repérer les adresses IP qui scannent très lentement pour éviter d'être repérées trop facilement, et de les bloquer avec un "ipset" bien placé dans votre pare-feu. Attention les adresses IP sont stockées dans le format interne de Mysql et il faut utiliser les fonctions "inet_aton" et "inet_ntoa".
Ici on sélectionne les IP qui ont "atteint" plus de 10 ports (sans données retournees) sur les 10 derniers jours :
select inet_ntoa(IP_SRC_ADDR) SRC,inet_ntoa(IP_DST_ADDR) DST, count(distinct L4_DST_PORT) NPORT from flowsv4 where FIRST_SWITCHED > UNIX_TIMESTAMP(DATE_SUB(now(), interval 10 day)) and IP_SRC_ADDR not between inet_aton('192.168.1.1') and inet_aton('192.168.3.255') and L4_DST_PORT < 32768 and OUT_BYTES 0 group by 1,2,4 having NPORT > 10 order by IP_SRC_ADDR; |
Ne pas oublier de ne sélectionner que les ports inférieurs à la limite sur votre système :
sudo sysctl -a 2>/dev/null | grep local_port_range
afin de ne pas bloquer de clients légitimes.
Cet ordre permet de repérer les adresses IP d'origine de scans lents sur 10 jours (ou plus si votre historique est plus long) concernant plus de 10 ports différents.
Il est très facile ensuite à partir de la liste obtenue de bloquer ces adresses en les intégrant dans un "set" exploité dans un pare-feu.
L'exécution de ce script peut être assez longue selon le nombre de rangs contenus dans la table principale malgré un index favorable sur le timestamp, mais il peut être lancé quelques fois chaque jour sans surcharge excessive.
Ici ce type de recherche est exploité "manuellement" pour tenir à jour une liste d'adresses IP à éviter, voir article spécifique ici.