Guide d’intégration
Datasets Suricata d’IP et de domaines malveillants, rechargés avec les règles
Aucune carte bancaire requise · Clé API gratuite
Sur cette page08
Ce que vous obtenez
Chaque liste devient un fichier de dataset, deux pour les IP. Un dataset chargé depuis un fichier lève lui-même son plafond de mémoire, sauf si datasets.defaults.memcap est fixé ; son hashsize doit rester proche du nombre d’entrées.
| Liste | Entrées | Régénérée | Offres |
|---|---|---|---|
blocklist-ips-critical.txtPar défaut : datasets ismalicious-ips4 (type ipv4) et ismalicious-ips6 (type ip), sur ip.dst et ip.src. IP signalées par 6 sources de menaces ou plus, ou par 3 ou plus avec une catégorie critique. | environ 89 000 | toutes les 12 h | Basic, Pro et Enterprise |
blocklist-domains-c2.txtDataset ismalicious-c2-domains, de type string, sur dns.query, http.host et tls.sni : domaines de commande et contrôle (C2). | environ 22 000 | toutes les 12 h | Basic, Pro et Enterprise |
blocklist-domains-ransomware.txtDataset ismalicious-ransomware-domains, de type string, sur dns.query : domaines de la catégorie ransomware. | environ 3 600 | toutes les 12 h | Basic, Pro et Enterprise |
Nombres arrondis d’après la génération du ; chaque liste est régénérée toutes les 12 heures. Les chiffres du jour sont publics et ne demandent aucune clé.
Ce que reçoit chaque offre
- FreeCompte Free, ou aucune clé : les premiers 10 % de chaque liste, signalés par
X-Blocklist-Version: lite. - Basic, Pro et EnterpriseBasic, Pro et Enterprise : toutes les listes, complètes.
- Pro et EnterpriseCollections TAXII 2.1, pour les plateformes qui lisent les indicateurs STIX : Pro et Enterprise.
GET https:/
Liste complète ou échantillon de 10 %
| Champ | Basic, Pro et Enterprise | Free |
|---|---|---|
X-Blocklist-Version: | full | lite |
X-Blocklist-Percentage: | 100 | 10 |
Total entries: | <COUNT> | <COUNT> |
Premières lignes du fichier
# IsMalicious.com Blocklist - IPs (Critical)
# Format: Plain
# Generated: <BUILD_TIME>
# Total entries: <COUNT>
# Update frequency: every 12 hours
# Category: All
# Threat level: Critical
# Website: https://ismalicious.com
# © <YEAR> IsMalicious (compilation). Licensed to the downloading account under https://ismalicious.com/terms; redistribution of the compilation prohibited. Third-party entries remain under their providers' licences — see https://ismalicious.com/sources.
#Les valeurs entre chevrons sont fixées à chaque génération.
Prérequis
- Suricata 7.0 ou 8.0, vérifié sur 7.0.17 et 8.0.7. Les règles DNS et TLS mettent le nom en minuscules avec
to_lowercase, qui demande 7.0.3 ou ultérieur. - Un accès root à la sonde, avec
curl,awketperl. - Une clé API et son secret isMalicious, dans Compte › Accès API.
- Un accès HTTPS sortant (TCP 443) en IPv4 depuis la sonde vers
api.ismalicious.com, qui n’a pas d’adresse IPv6.
Mise en place
Copier la clé API et le secret
Ouvrez Compte › Accès API et copiez la Clé API et le Secret API. Les listes complètes demandent une offre Basic, Pro ou Enterprise ; avec une clé Free, le script reçoit l’échantillon de 10 % et le refuse.Stocker les identifiants sur la sonde
Créez/etc/ismalicious/netrc, réservé à root, avec les commandes ci-dessous, puis écrivez-y les trois lignes avec un éditeur : tapées dans un shell, elles finiraient dans son historique. curl y lit la clé et le secret : ils n’apparaissent jamais sur une ligne de commande.Créer le fichier, réservé à rootsh install -d -m 700 /etc/ismalicious [ -e /etc/ismalicious/netrc ] || install -m 600 /dev/null /etc/ismalicious/netrc chmod 600 /etc/ismalicious/netrc # Then write the three lines below into it with an editor, unless it holds them already./ etc/ ismalicious/ netrcnetrc machine api.ismalicious.com login <API_KEY> password <API_SECRET>Installer le script de conversion et l’exécuter une fois
- Enregistrez le script sous
/, en mode 700, et exécutez-le.usr/ local/ sbin/ ismalicious-suricata. sh - Il refuse une erreur, un contenu qui n’est pas une liste, l’échantillon de 10 % et un fichier dont le nombre d’entrées diffère de son en-tête, retire les lignes d’en-tête
#, écrit les adresses IPv4 et IPv6 dans deux fichiers, car Suricata 8.0 refuse l’IPv4 dans un dataset de type ip, et le base64 de chaque domaine pour les datasets string, comme Suricata l’exige. - Il déplace ensuite les fichiers dans
/etc/suricata/ismalicious/; en cas d’échec, les fichiers en service restent tels quels.
/ usr/ local/ sbin/ ismalicious-suricata. shsh #!/bin/sh # Download isMalicious lists and write Suricata dataset files. On any failure # the files in service stay as they are. set -eu DIR=/etc/suricata/ismalicious NETRC=/etc/ismalicious/netrc mkdir -p "$DIR" # Temporary directory on the same file system, so the final mv is atomic. T=$(mktemp -d "$DIR/.tmp.XXXXXX") trap 'rm -rf "$T"' EXIT # fetch_list LIST OUT: download one list to OUT and check it. # On any failure OUT is removed and the function returns 1. fetch_list() { if ! code=$(curl --silent --show-error --fail --netrc-file "$NETRC" \ --proto '=https' --max-time 300 --retry 2 \ --output "$2" --write-out '%{http_code}' "https://api.ismalicious.com/blocklist/download/$1"); then rm -f "$2"; echo "$1: download failed" >&2; return 1 fi if [ "$code" != 200 ]; then rm -f "$2"; echo "$1: HTTP $code" >&2; return 1 fi if ! head -n 1 "$2" | grep -q '^[#!] IsMalicious.com Blocklist'; then rm -f "$2"; echo "$1: not an isMalicious list" >&2; return 1 fi if grep -q 'Lite Version' "$2"; then rm -f "$2"; echo "$1: lite list received, check the API key and the plan" >&2 return 1 fi # Every entry ends with a newline, and one header counts them: refuse a # cut, doubled or empty file. if [ -n "$(tail -c 1 "$2")" ]; then rm -f "$2"; echo "$1: cut short, no final newline" >&2; return 1 fi if [ "$(grep -c '^[#!] Total entries:' "$2")" != 1 ]; then rm -f "$2"; echo "$1: not one Total entries line" >&2; return 1 fi total=$(sed -n 's/^[#!] Total entries: \([0-9,]*\)$/\1/p' "$2" | tr -d ,) got=$(grep -c '^[^#!]' "$2" || true) if [ -z "$total" ] || [ "$total" = 0 ] || [ "$got" != "$total" ]; then rm -f "$2"; echo "$1: $got entries, the header says ${total:-none}" >&2 return 1 fi } fetch_list blocklist-ips-critical.txt "$T/ips-critical" fetch_list blocklist-domains-c2.txt "$T/domains-c2" fetch_list blocklist-domains-ransomware.txt "$T/domains-ransomware" # Suricata 8.0 reads every line of a type ip set as IPv6 and rejects IPv4 # (OISF bug 9006): IPv4 goes to a type ipv4 set, IPv6 to a type ip set. awk '!/^[#!]/ && NF && !index($1, ":") { print $1 }' "$T/ips-critical" > "$T/ismalicious-ips4.lst" awk '!/^[#!]/ && NF && index($1, ":") { print $1 }' "$T/ips-critical" > "$T/ismalicious-ips6.lst" # Dataset type string: base64 of each domain, no trailing newline in the value. for l in c2 ransomware; do awk '!/^[#!]/ && NF { print $1 }' "$T/domains-$l" \ | perl -MMIME::Base64 -ne 'chomp; print encode_base64($_, ""), "\n"' \ > "$T/ismalicious-$l-domains.lst" done for f in ismalicious-ips4.lst ismalicious-ips6.lst \ ismalicious-c2-domains.lst ismalicious-ransomware-domains.lst; do chmod 644 "$T/$f" mv "$T/$f" "$DIR/$f" done- Enregistrez le script sous
Ajouter les règles
Enregistrez les règles sous/, à côté des fichiers de datasets : un cheminetc/ suricata/ ismalicious/ ismalicious. rules loadest relatif au fichier de règles. Prenez les SID dans votre plage locale. Les règles d’IP visent le sens client vers serveur de chaque session (flow:to_server) et n’alertent qu’une fois par heure par paire d’adresses ; décommentez la paire IPv6 dès queismalicious-ips6.lstcontient des entrées. Sous Suricata 7.0.0 à 7.0.2, retirezto_lowercase;. En mode IPS, remplacezalertpardrop./ etc/ suricata/ ismalicious/ ismalicious. rulesSuricata # IPv4, both directions (Suricata 7.0 and later) alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:"isMalicious critical IP outbound"; flow:to_server; ip.dst; dataset:isset,ismalicious-ips4, type ipv4, load ismalicious-ips4.lst, hashsize 65536; threshold:type limit, track by_both, count 1, seconds 3600; classtype:bad-unknown; sid:1900001; rev:2;) alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"isMalicious critical IP inbound"; flow:to_server; ip.src; dataset:isset,ismalicious-ips4, type ipv4, load ismalicious-ips4.lst, hashsize 65536; threshold:type limit, track by_both, count 1, seconds 3600; classtype:bad-unknown; sid:1900002; rev:2;) # IPv6: uncomment when ismalicious-ips6.lst is not empty. # alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:"isMalicious critical IPv6 outbound"; flow:to_server; ip.dst; dataset:isset,ismalicious-ips6, type ip, load ismalicious-ips6.lst, hashsize 4096; threshold:type limit, track by_both, count 1, seconds 3600; classtype:bad-unknown; sid:1900003; rev:1;) # alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"isMalicious critical IPv6 inbound"; flow:to_server; ip.src; dataset:isset,ismalicious-ips6, type ip, load ismalicious-ips6.lst, hashsize 4096; threshold:type limit, track by_both, count 1, seconds 3600; classtype:bad-unknown; sid:1900004; rev:1;) # Domains (on Suricata 7.0.0 to 7.0.2, remove "to_lowercase;") alert dns $HOME_NET any -> any any (msg:"isMalicious C2 domain in DNS query"; dns.query; to_lowercase; dataset:isset,ismalicious-c2-domains, type string, load ismalicious-c2-domains.lst, hashsize 32768; classtype:trojan-activity; sid:1900010; rev:1;) alert http $HOME_NET any -> any any (msg:"isMalicious C2 domain in HTTP Host"; flow:established,to_server; http.host; dataset:isset,ismalicious-c2-domains, type string, load ismalicious-c2-domains.lst, hashsize 32768; classtype:trojan-activity; sid:1900011; rev:1;) alert dns $HOME_NET any -> any any (msg:"isMalicious ransomware domain in DNS query"; dns.query; to_lowercase; dataset:isset,ismalicious-ransomware-domains, type string, load ismalicious-ransomware-domains.lst, hashsize 4096; classtype:trojan-activity; sid:1900012; rev:1;) alert tls $HOME_NET any -> any any (msg:"isMalicious C2 domain in TLS SNI"; flow:established,to_server; tls.sni; to_lowercase; dataset:isset,ismalicious-c2-domains, type string, load ismalicious-c2-domains.lst, hashsize 32768; classtype:trojan-activity; sid:1900013; rev:1;)Ajouter le fichier de règles à suricata.yaml
Ajoutez le fichier de règles àrule-filesdanssuricata.yaml, testez la configuration avecsuricata -T, qui charge les règles et les datasets sans lancer la capture (avec-vvv, il affiche aussi chaque dataset chargé), puis redémarrez Suricata une fois.suricata. yamlyaml # Merge into the existing key: rule-files: - suricata.rules - /etc/suricata/ismalicious/ismalicious.rulesTester la configurationsh suricata -T -c /etc/suricata/suricata.yaml # The datasets as loaded, at config verbosity: suricata -T -c /etc/suricata/suricata.yaml -vvv 2>&1 | grep 'dataset:'Planifier le script et un rechargement des règles
Lancez le script, puis un rechargement des règles, toutes les 12 heures depuis/: les listes sont régénérées toutes les 12 heures, et un rechargement relit sur le disque les datasets définis seulement paretc/ cron. d/ ismalicious-suricata load. cron tourne avec un PATH court, d’où la ligne PATH poursuricatasc, qui a besoin du socket unix, actif par défaut ; sans lui, envoyez plutôtkill -USR2à Suricata./ etc/ cron. d/ ismalicious-suricatacron PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 17 3,15 * * * root /usr/local/sbin/ismalicious-suricata.sh && suricatasc -c reload-rules
Vérifier le résultat
suricata -Tse termine sans erreur de dataset.suricata -T … -vvvaffichedataset: ismalicious-c2-domainspour chaque dataset (le niveau par défaut deloading from suricata.logne l’enregistre pas), etsuricatascne liste aucune règle isMalicious après un rechargement.-c ruleset-failed-rules - Les deux fichiers d’IP contiennent ensemble le
countde la liste dans /blocklist/stats, à une régénération près, et chaque fichier de domaines celui de sa liste. dataset-lookupviasuricatasctrouve un domaine listé, donné en base64.- Résoudre un domaine C2 listé depuis un hôte de
$HOME_NETécrit une alerte avec lesignature_id1900010 danseve.json. - Les premières lignes d’un téléchargement direct montrent
Total entriessansLite Version.
# Entries per dataset file:
wc -l /etc/suricata/ismalicious/*.lst
# Rules the last reload dropped (none expected):
suricatasc -c ruleset-failed-rules
# Is a domain in the dataset? (unix socket, 7.0 and 8.0)
suricatasc -c "dataset-lookup ismalicious-c2-domains string $(printf '%s' <LISTED_DOMAIN> | base64 -w0)"
# As root (the netrc file is root-only): the key reaches isMalicious when
# Total entries has no "Lite Version".
sudo curl -sS --netrc-file /etc/ismalicious/netrc \
https://api.ismalicious.com/blocklist/download/blocklist-ips-critical.txt | head -12Dépannage
Le script s’arrête sur un 401
La clé ou le secret du fichier netrc est faux ou incomplet : curl sort avec le code 22, le script s’arrête avant de toucher aux fichiers en service, et Suricata garde les précédents. Le corps de la réponse indique « Blocklist not found or empty » ; fiez-vous au code HTTP. Régénérer la clé dans Compte › Accès API invalide l’ancienne paire.
« lite list received »
Aucun identifiant n’est parvenu au serveur, ou l’offre est Free ou interrompue : un abonnement impayé, en retard de paiement, annulé, incomplet ou suspendu compte comme Free. Vérifiez l’entrée netrc et l’offre.
« entries, the header says », « cut short, no final newline » ou « not one Total entries line »
Le fichier était vide, tronqué ou n’était pas une des listes, comme quand un proxy ou un portail captif répond. Le script s’arrête avant de toucher aux fichiers en service ; l’exécution suivante réessaie.
Délais dépassés ou 502
Un téléchargement qui prend plus de 30 secondes de notre côté finit en délai dépassé ou en 502 : prenez une liste par niveau ou par catégorie du tableau.
503 avec Retry-After: 600
Une liste est en cours de génération. L’exécution suivante la récupère.
« invalid Ipv6 value » pour ismalicious-ips
Suricata 8.0 lit chaque ligne d’un dataset de type ip comme de l’IPv6 et refuse les adresses IPv4 (bogue OISF 9006) ; suricata -T échoue alors. Gardez les adresses IPv4 dans le dataset de type ipv4 qu’écrit le script, ismalicious-ips4.lst.
« bad base64 encoding » ou « invalid Ipv4 value »
Un dataset string contient des domaines en clair au lieu de base64, ou une règle charge le mauvais fichier dans un dataset (en 7.0, le message est « dataset data parse failed »). Utilisez les fichiers du script, chacun avec sa règle.
« hashsize … exceeds configured 'single-hashsize' limit »
Ramenez hashsize à 65 536 ou moins en 8.0 (262 144 à partir de 7.0.9), ou relevez datasets., ce qui demande un redémarrage.
« dataset … load mismatch »
Deux règles utilisent le même nom de dataset avec des fichiers load différents. Gardez un fichier par nom.
Aucune alerte DNS sous Suricata 7.0.0 à 7.0.2
La requête n’était pas en minuscules : to_lowercase existe à partir de 7.0.3, et les listes contiennent des noms en minuscules. Mettez à jour, ou acceptez que les requêtes en casse mixte ne correspondent pas.
curl sort avec le code 60
Mettez à jour le magasin d’autorités, vérifiez l’horloge, et exemptez api.ismalicious.com de l’inspection TLS.
Limites
- Les datasets ne correspondent qu’à la valeur listée. La correspondance des sous-domaines demande
match subdomainavec des entrées préfixées d’un point, qui existe à partir de Suricata 8.0.7 (absent en 8.0.6) ; ces fichiers contiennent des noms exacts. - La réputation d’IP (
iprep) n’est pas couverte : chaque entrée occupe une place dans la table des hôtes, dont Suricata ne documente pas la taille, et une table pleine arrête le chargement du fichier. - Un rechargement construit un second moteur de détection avant de libérer le premier : les datasets sont un instant en mémoire deux fois.
- Aucun fichier CIDR, RPZ, CSV ou JSON n’est servi : le script construit les fichiers dont Suricata a besoin à partir des listes simples.
- Les listes d’empreintes ne sont pas couvertes : les mots-clés d’empreintes de fichiers de Suricata demandent des réglages d’inspection de fichiers que ce guide n’a pas vérifiés.
- L’échantillon de 10 % est le premier dixième d’un fichier non trié, pas le dixième le plus risqué : le script le refuse.
Questions fréquentes
Suricata peut-il télécharger une blocklist lui-même ?
Non. Suricata ne lit que des fichiers locaux. Un script cron sur la sonde télécharge les listes isMalicious avec curl, les écrit en fichiers de datasets, et un rechargement des règles les charge.
Pourquoi les fichiers de domaines sont-ils en base64 ?
Les datasets string de Suricata prennent une valeur base64 par ligne, en 7.0 comme en 8.0. Le script encode chaque domaine sans son retour à la ligne final, pour que la valeur corresponde au nom vu dans le trafic.
Pourquoi des datasets plutôt que la réputation d’IP ?
La réputation d’IP range chaque adresse dans la table des hôtes, dont Suricata ne documente pas la mémoire par entrée, et une table pleine arrête le chargement du fichier. Un dataset chargé depuis un fichier lève lui-même son plafond de mémoire.
Chaque mise à jour demande-t-elle un redémarrage de Suricata ?
Non. Un rechargement des règles, par suricatasc ou un signal USR2, relit sur le disque les datasets définis seulement par load. Ne redémarrez qu’après avoir modifié suricata.yaml.
À voir aussi
Listes en lookups, threat lists ES, envoi par HEC
Collections TAXII 2.1 pour les règles indicator match
IP et domaines malveillants en listes CDB pour les règles Wazuh
IP et domaines malveillants en reference sets QRadar
Indicateurs TAXII 2.1 dans Sentinel
Toutes les listes, niveaux et catégories
Collections TAXII 2.1 pour SIEM et TIP
Authentification, endpoints et limites
Vérifier un domaine avant de le bloquer
Commencer
Prêt à commencer ?
Aucune carte bancaire requise · Clé API gratuite