--- categories: mail title: Howto Antispam ... Le [SPAM](https://fr.wikipedia.org/wiki/Spam) est un message électronique non sollicité. C'est devenu un fléau moderne, au même titre que les virus informatiques ou les attaques DDOS, qui arrange bien des industriels… ## Les outils de base ~~~ # apt install postfix spamassassin amavisd-new clamav-daemon postgrey ~~~ ## Les principes de base Si un utilisateur détecte d'un coup d'œil si un message est un spam ou non... c'est compliqué d'automatiser cette décision par un ordinateur. Voici les principes qui sont généralement mis en œuvre : * Vérification de l'adresse email de l'expéditeur * Vérification de l'adresse IP de l'expéditeur * Vérification des entêtes et du contenu du message * Vérification des pièces jointes * Vérification des éventuelles signatures (DKIM) * Vérification du client SMTP qui transmet le message Au niveau d'un serveur, un ensemble d'outils vont se charger de ces vérifications. On distingue souvent : * Les filtres de 1er niveau : vérifications *avant* d'accepter un message par le serveur SMTP * Les filtres de 2ème niveau : vérifications *après* l'avoir accepté mais *avant* de délivrer dans la boîte de l'utilisateur * Les filtres de 3ème niveau : vérifications faites par l'utilisateur (antivirus sur son poste, filtres sur son client POP/IMAP) => non traité dans ce Howto ## Postfix [Postfix](HowtoPostfix) est un serveur SMTP. Il est la base d'un antispam car c'est lui qui reçoit les messages via le protocole SMTP. Il permet déjà un grand nombre de vérifications basiques : * rejet à partir d'une liste "statique" d'adresses email / d'adresses IP * rejet à partir de termes simples dans les entêtes et le contenu * rejet des noms de domaine inexistants ou invalides utilisés dans l'adresse email de l'expéditeur * rejet des adresses IP qui ont un reverse DNS inexistant ou invalide * rejet à partir d'une RBL Voici un exemple de restrictions à mettre dans le `main.cf` : ~~~ # Restrictions selon l'IP smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_rbl_client clients.rbl.gcolpart.com, cidr:/etc/postfix/spamd.cidr, permit # Exiger la commande HELO/EHLO smtpd_helo_required = yes # Restrictions au niveau de la commande HELO/EHLO smtpd_helo_restrictions = reject_invalid_hostname # Restrictions au niveau de la commande MAIL FROM smtpd_sender_restrictions = permit_mynetworks, check_sender_access hash:/etc/postfix/sa-blacklist.access, permit # Restrictions au niveau de la commande RCPT TO smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_client_access hash:/etc/postfix/client.access_local, check_client_access hash:/etc/postfix/client.access, check_sender_access hash:/etc/postfix/sender.access_local, check_sender_access hash:/etc/postfix/sender.access, check_recipient_access hash:/etc/postfix/recipient.access_local, check_recipient_access hash:/etc/postfix/recipient.access, reject_unlisted_recipient, reject_unknown_sender_domain, reject_non_fqdn_sender, reject_unauth_pipelining, permit # Restrictions au niveau de la commande DATA smtpd_data_restrictions = permit # Restrictions au niveau de la commande ETRN smtpd_etrn_restrictions = reject # Filtrage des entetes header_checks = regexp:/etc/postfix/header_kill_local, regexp:/etc/postfix/header_kill # Filtrage du contenu body_checks = regexp:/etc/postfix/body_kill_local, regexp:/etc/postfix/body_kill ~~~ Cette configuration suppose avec des "maps" locales vides : ~~~ # touch /etc/postfix/client.access_local # postmap /etc/postfix/client.access_local # touch /etc/postfix/sender.access_local # postmap /etc/postfix/sender.access_local # touch /etc/postfix/recipient.access_local # postmap /etc/postfix/recipient.access_local # touch /etc/postfix/header_kill_local ~~~ Cela suppose aussi de récupérer des maps gérées par Evolix à l'aide d'un script spam.sh : ~~~ #!/bin/bash # debug #set -x umask 022 tmp_file=$(mktemp) tmp=$(mktemp -d) cd $tmp if [ -f $tmp_file ] ; then rm $tmp_file ; fi cd /var/tmp sleep $[ $RANDOM / 1024 ] wget -q -t 3 -O $tmp_file cp $tmp_file /etc/postfix/client.access rm $tmp_file wget -q -t 3 -O $tmp_file cp $tmp_file /etc/postfix/sender.access rm $tmp_file wget -q -t 3 -O $tmp_file cp $tmp_file /etc/postfix/recipient.access rm $tmp_file wget -q -t 3 -O $tmp_file cp $tmp_file /etc/postfix/header_kill rm $tmp_file wget -q -t 3 -O sa-blacklist.access wget -q -t 3 -O $tmp_file if md5sum -c $tmp_file > /dev/null && [ -s sa-blacklist.access ] ; then cp sa-blacklist.access /etc/postfix/sa-blacklist.access fi rm sa-blacklist.access rm $tmp_file /usr/sbin/postmap hash:/etc/postfix/client.access /usr/sbin/postmap hash:/etc/postfix/sender.access /usr/sbin/postmap hash:/etc/postfix/recipient.access /usr/sbin/postmap -r hash:/etc/postfix/sa-blacklist.access wget -q -t 3 -O spamd.cidr wget -q -t 3 -O $tmp_file if md5sum -c $tmp_file > /dev/null && [ -s spamd.cidr ] ; then cp spamd.cidr /etc/postfix/spamd.cidr fi rm spamd.cidr rm $tmp_file rm -rf $tmp ~~~ ### Postscreen Postscreen est un démon de [Postfix](HowtoPostfix) qui permet de renforcer les filtres de 1er niveau. Il permet principalement de combiner la vérification auprès de plusieurs RBL. Avec l'option `reject_rbl_client`, Postfix vérifie la présence d'une IP auprès de plusieurs RBLs : si l'IP est présente au moins une fois, Postfix rejette le message. Postscreen permet de ne rejeter le message que si l'adresse IP est présente au moins N fois. Sa configuration se passe dans le fichier `/etc/postfix/main.cf` : ~~~ # Deep protocol tests # Disabled due to reject with 450. postscreen_pipelining_enable = no postscreen_non_smtp_command_enable = no postscreen_bare_newline_enable = no # Pre 220 tests. postscreen_greet_banner = Welcome! Are you a zombie? # RBL # If score >=2, reject with 550 postscreen_dnsbl_threshold = 10 postscreen_dnsbl_sites = zen.spamhaus.org=127.0.0.[2..11]*9, bl.spamcop.net*9, b.barracudacentral.org*8, bl.score.senderscore.com*8, hostkarma.junkemailfilter.com=127.0.0.2*8, ix.dnsbl.manitu.net*6, psbl.surriel.com*5, truncate.gbudb.net*5, dnsbl-1.uceprotect.net*5, db.wpbl.info*5, all.spamrats.com*5, dnsbl.dronebl.org*5, dnsbl.inps.de*5, bl.blocklist.de*5, all.s5h.net*5, bl.mailspike.net*5, cidr.bl.mcafee.com*5, hostkarma.junkemailfilter.com=127.0.0.3*4, dnsblchile.org*1, hostkarma.junkemailfilter.com=127.0.0.1*-6 #dnsblchile.org #rbl.rbldns.ru #dnsbl.proxybl.org # Skip all tests if score <=-1 postscreen_dnsbl_whitelist_threshold = -1 # Actions postscreen_dnsbl_action = enforce postscreen_greet_action = enforce postscreen_bare_newline_action = enforce postscreen_blacklist_action = enforce postscreen_non_smtp_command_action = drop postscreen_pipelining_action = enforce # Whitelist & MX kick # If you talk first to high MX weight (192.0.2.34) = Reject with 550. postscreen_whitelist_interfaces = !192.0.2.34, static:192.0.2.32, static:192.0.2.24 postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr, hash:/etc/postfix/client.access, hash:/etc/postfix/client.access_local # Cache controls postscreen_cache_retention_time = 10s postscreen_greet_ttl = 1d postscreen_bare_newline_ttl = 30d postscreen_non_smtp_command_ttl = 30d postscreen_pipelining_ttl = 30d ~~~ > *Note* : pour les fichiers listés dans `postscreen_access_list`, tout mot clé différent de `permit` rejette les adresses IP listées (y compris `OK` !). ### Postgrey [Postgrey](http://postgrey.schweikert.ch/) fait du Greylisting : il retarde volontairement un message reçu pour vérifier le client SMTP qui envoie le message. Cela a une certaine efficacité, d'autant plus que cela permet de faire d'autres vérifications plus tard... qui seront de meilleures qualité car plus à jour ! Mais si l'on fait cela pour tous les messages reçus, la plupart des messages seront retardés de quelques minutes... ou heures. Souvent, on ne tolère donc pas une activation globale du Greylisting. Cela reste néanmoins intéressant : on peut s'en servir pour retarder des messages incertains et attendre d'avoir des vérifications de meilleure qualité. ### Whitelister Whitelister est un logiciel écrit en OCAML par Pierre Habouzit. Il permet de faire du Greylisting conditionnel, c'est-à-dire qu'il permet de ne faire du Greylist que si l'adresse IP est « louche ». Pour cela il teste principalement sa présence dans des RBL : si elle est listée par au moins une RBL, le message est greylisté ! ~~~ # aptitude install whitelister postgrey ~~~ Dans `/etc/whitelister.conf` : ~~~ sock: /var/spool/postfix/private/whitelister.ctl #rbl: zen.spamhaus.org rbl: bl.spamcop.net #rbl: b.barracudacentral.org #rbl: cbl.abuseat.org #rbl: dnsbl.sorbs.net rbl: ix.dnsbl.manitu.net rbl: psbl.surriel.com rbl: truncate.gbudb.net rbl: dnsbl-1.uceprotect.net rbl: db.wpbl.info rbl: all.spamrats.com rbl: block.stopspam.org rbl: badhost.stopspam.org rbl: dnsbl.stopspam.org rbl: dul.pacifier.net rbl: dnsbl.dronebl.org rbl: dnsbl.inps.de rbl: bl.blocklist.de rbl: all.s5h.net rbl: bl.score.senderscore.com #rbl: rbl.rbldns.ru rbl: dnsbl.cobion.com rbl: bl.mailspike.net #rbl: cidr.bl.mcafee.com #rbl: dnsblchile.org #rbl: aspews.ext.sorbs.net #rbl: l2.spews.dnsbl.sorbs.net dns_client: 1 dns_rev_client: 1 verb: 0 ~~~ Ajouter la ligne à la directive `smtpd_recipient_restrictions` du fichier `/etc/postfix/main.cf` : ~~~ check_policy_service unix:private/whitelister.ctl check_policy_service inet:127.0.0.1:60000, ~~~ Puis redémarrer Postfix. ## RBL : Realtime Blackhole List Une RBL est un système permet de vérifier la présence d'adresses IP, de noms de domaine, etc. dans une base mise à jour très régulièrement. La plupart du temps, son interrogation fonctionne via les DNS. ### DNS RBL pour les adresses IP Les RBLs pour IP permettent de vérifier si une adresse IP est légitime pour envoyer des emails. Par exemple, pour vérifier si une adresse IP est légitime : ~~~ $ dig +short 2.26.171.202.clients.rbl.gcolpart.com 127.0.0.2 => NON LÉGITIME $ dig +short 8.8.8.8.clients.rbl.gcolpart.com ~~~ Il existe de très nombreuses RBLs pour IP... le problème est leur fiabilité et leur politique pour en sortir. Voici une liste de RBLs que nous utilisons (ou pas) : | RBL | Notre confiance | Lien (optionel) | |-----|-----------------|-----------------| |clients.rbl.gcolpart.com|100%|| |zen.spamhaus.org (127.0.0.X)|90%| (depuis 2020 possible d'avoir des réponses en 127.255.255.25X si rate-limiting etc.)| |bl.spamcop.net|90%|| |b.barracudacentral.org|80%| (parfois très lent à répondre, note d'avril 2024)| |cbl.abuseat.org|80%| (inutile, racheté par SpamHaus début 2021)| |bl.score.senderscore.com|80%|| |hostkarma.junkemailfilter.com (127.0.0.2)|80%| (attention 127.0.0.1 signifie liste blanche)| |dnsbl.sorbs.net|70%| (parfois très lent à répondre, note d'avril 2024)| |ix.dnsbl.manitu.net|60%|| |psbl.surriel.com|50%|| |truncate.gbudb.net|50%|| |dnsbl-1.uceprotect.net|50%|| |db.wpbl.info|50%|| |all.spamrats.com|50%|| |dnsbl.dronebl.org|50%|| |dnsbl.inps.de|50%|| |bl.blocklist.de|50%|| |srnblack.surgate.net|50%| (indispo depuis le 30 avril 2019)| |all.s5h.net|50%|| |rbl.megarbl.net|50%| (indispo depuis 2019)| |dnsbl.cobion.com|50%|| |bl.mailspike.net|50%|| |cidr.bl.mcafee.com|50%| (semble indispo ce jour, sept 2023)| |bl.spamcannibal.org|40%| (indispo depuis juin 2019)| |work.drbl.gremlin.ru|40%| (parfois très lente à répondre)| |aspews.ext.sorbs.net|20%| (parfois très lent à répondre, note d'avril 2024)| |l2.spews.dnsbl.sorbs.net|10%| ?| |rbl.rbldns.ru|10%| (parfois très lent à répondre)| |dnsblchile.org|10%|| |dnsbl.stopspam.org|0%|| |dnsbl.proxybl.org|0%|| |pbl.spamhaus.org|N/A| (inclus dans `zen.spamhaus.org`)| ### RBL pour les domaines expéditeur / HELO est particulier, cela liste tous les domaines qui ne respectent pas les RFC, y compris GMAIL & co :) Attention, RFC^2 (RFC Clueless) s'est arrêté définitivement en 2023. ### URIBL : les RBLS pour les URI / noms de domaines Les RBLs pour URI permettent de vérifier si un nom de domaine est légitime, principalement pour les liens dans le contenu des emails. Par exemple, pour vérifier si un domaine est légitime : ~~~ $ dig +short cryptolocker.com.multi.uribl.com 127.0.0.2 => NON LÉGITIME $ dig +short example.com.multi.uribl.com ~~~ * multi.uribl.com : * dbl.spamhaus.org : * multi.surbl.org : * hostkarma.junkemailfilter.com : * public.sarbl.org : * dnsbl.invaluement.com : (payant) ## Vérifications via SPF L'idée est de rejetter un mail qui a un enregistrement SPF invalide. On utilise pour cela un programme en python `postfix-policyd-spf-python` (dispo dans les packages Debian). La configuration se fait dans /etc/postfix-policyd-spf-python/policyd-spf.conf, on peut se servir de la version commenté : /usr/share/doc/postfix-policyd-spf-python/policyd-spf.conf.commented, c'est celle que l'on va utiliser. ~~~ # cp /usr/share/doc/postfix-policyd-spf-python/policyd-spf.conf.commented /etc/postfix-policyd-spf-python/policyd-spf.conf ~~~ Paramètres intéressants : ~~~ defaultSeedOnly = 0 # Mode simulation, aucun rejet, seulement la description de l'action dans les logs. Mail_From_reject = Fail # Rejete les mails si le check SPF échoue. Mail_From_reject = Softfail # Rejete les mails si le check SPF échoue même en « soft » (utilisation de ~all par exemple), non recommandé. Reject_Not_Pass_Domains = aol.com,hotmail.com # Transoforme un ~all en -all pour des domaines en particuliers. ~~~ Pour l'activer, modifications dans `/etc/postfix/master.cf` : master.cf: ~~~ policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf ~~~ et `/etc/postfix/main.cf` : ~~~ smtpd_recipient_restrictions = ... reject_unauth_destination check_policy_service unix:private/policyd-spf ... policyd-spf_time_limit = 3600 ~~~ Un redémarrage de postfix sera nécessaire. ## Vérification via DKIM La norme [DKIM](https://fr.wikipedia.org/wiki/DomainKeys_Identified_Mail) permet de vérifier les messages avec un entête `DKIM-Signature:`. Voir ## Vérification via DMARC La spécification [DMARC](https://fr.wikipedia.org/wiki/DMARC) permet de rejeter ou mettre des messages en quarantaine si ils ne sont pas conformes aux vérifications SPF et/ou DKIM. Pour implémenter cela, il faut utiliser le package **opendmarc** : ## Opendmarc Opendmarc est un service qui permet de faire de la verification DMARC et / ou DKIM. En rajoutant l'entête "Authentication-Results" et selon comment on le configure, il peux juste notifier le résultat dans les entêtes du mail ou rejeter les mails si le résultat est négatif. ### Intégration d'Opendmarc à Postfix Pour commencer, installons le paquet opendmarc : ~~~ # apt install opendmarc ~~~ Puis configurer le fichier _/etc/opendmarc.conf_ : ~~~ AuthservID mail.example.com PidFile /var/run/opendmarc/opendmarc.pid PublicSuffixList /usr/share/publicsuffix Socket inet:12345@localhost Syslog true UMask 0002 UserID opendmarc ~~~ Dans cette configuration, on veux qu'Opendmarc écoute sur le port 12345 en local. Si on veux qu'il écoute sur un fichier .socket, on ajuste la variable `Socket` comme ceci : ~~~ Socket local:/var/run/opendmarc/opendmarc.sock ~~~ Voici d'autres directives utiles: `AuthservID` doit avoir pour valeur le hostname du serveur, par default il prend la valeur du MTA du serveur. `RejectFailures` : true ou false. Si défini a `true` alors les mails qui ne passerons pas la vérification DMARC et seront rejetés. Défini à false par défaut. `TrustedAuthservIDs` : Liste des `AuthservIDs` necessitant la validation DMARC, utile lorsque plusieurs MX sont présent sur le même serveur. `SoftwareHeader` : Ajoute une entête 'Dmarc-Filter' avec la version opendmarc dans chaque mail, utile pour une phase de test. On peux définir aussi une liste de 'Host' (IPs) a ignorer dans le fichier _/etc/opendmarc/ignore.hosts_ On démarre Opendmarc et on l'active au démarrage : ~~~ # systemctl start opendmarc # systemctl enable opendmarc ~~~ Ensuite on doit ajouter opendmarc en tant que Milter pour Postfix. Si l'on veux qu'Opendmarc récupère les informations de signature d'OpenDKIM, on le positionne juste après le port du milter 54321 d'Opendkim comme ceci : ~~~ # DKIM et Opendmarc non_smtpd_milters = inet:127.0.0.1:54321,inet:127.0.0.1:12345 smtpd_milters = inet:127.0.0.1:54321,inet:127.0.0.1:12345 in_flow_delay = 0s ~~~ On redémarre postfix : ~~~ # systemctl restart postfix ~~~ ### Vérifier et tester la configuration On peux vérifier la bonne configuration du domaine avec l'outil dmarc-inspector : Puis on envoie un mail sur le domaine concerné, et on doit voir les entêtes 'Authentication-Results'. Une pour DKIM si on a mis le milter DKIM avant celui d'Opendmarc, puis une deuxième pour DMARC : ~~~ Authentication-Results: mail.example.com; dkim=pass (1024-bit key; unprotected) header.d=evolix.fr header.i=@evolix.fr header.b="MS9KOG0U"; dkim-atps=neutral Authentication-Results: mail.example.com; dmarc=pass (p=none dis=none) header.from=evolix.fr ~~~ ## SpamAssassin Exemple de `local.cf` : ~~~ required_score 5 report_safe 0 rewrite_header Subject [SPAM] add_header all Report _REPORT_ # filtre bayesien # mkdir -p /var/spool/spam use_bayes 1 bayes_auto_learn 1 bayes_path /var/spool/spam/bayes bayes_file_mode 0777 # AWL : AutoWhitelist # mkdir -p /var/spool/spam loadplugin Mail::SpamAssassin::Plugin::AWL use_auto_whitelist 1 auto_whitelist_path /var/spool/spam/auto_whitelist auto_whitelist_file_mode 0666 # LANG TESTS Mail::SpamAssassin::Plugin::TextCat ok_languages en fr es it ok_locales en fr es it score BODY_8BITS 1.500 score CHARSET_FARAWAY 3.200 score CHARSET_FARAWAY_HEADER 3.200 score HTML_CHARSET_FARAWAY 0.500 score MIME_CHARSET_FARAWAY 2.450 score UNWANTED_LANGUAGE_BODY 2.800 # DCC # use_dcc 1 => un plugin maintenant... score DCC_CHECK 2.9 # RAZOR : use_razor2 1 razor_timeout 10 score RAZOR2_CHECK 2.9 score RAZOR2_CF_RANGE_51_100 1.3 # pyzor : use_pyzor 0 # RBL (Realtime Blackhole List) skip_rbl_checks 0 score RCVD_IN_BL_SPAMCOP_NET 3 # misc score HELO_DYNAMIC_IPADDR 0.3 score BIZ_TLD 0.1 score PRIORITY_NO_NAME 0.2 # disable HTML tests score HTML_MESSAGE 0 score HTML_00_10 0 score HTML_10_20 0 score HTML_20_30 0 score HTML_30_40 0 score HTML_40_50 0 score HTML_50_60 0 score HTML_60_70 0 score HTML_70_80 0 score HTML_80_90 0 score HTML_90_100 0 #score HTML_COMMENT_8BITS 0 score UPPERCASE_25_50 0 score UPPERCASE_50_75 0 score UPPERCASE_75_100 0 score MIME_HTML_ONLY 0.1 # From # Trop de faux negatifs avec BAYES_(0|1|2|3|4)* score BAYES_00 0 0 -0.01 -0.01 score BAYES_01 0 0 -0.01 -0.01 score BAYES_10 0 0 -0.01 -0.01 score BAYES_20 0 0 -0.01 -0.01 score BAYES_30 0 0 -0.01 -0.01 score BAYES_40 0 0 -0.01 -0.01 score BAYES_44 0 0 -0.01 -0.01 score BAYES_50 0 0 0.1 0.1 score BAYES_56 0 0 0.5 0.5 score BAYES_60 0 0 1.0 1.0 score BAYES_70 0 0 2.5 2.5 score BAYES_80 0 0 3.5 3.5 score BAYES_90 0 0 4.5 4.5 score BAYES_99 0 0 8.0 8.0 score RCVD_IN_SORBS_DUL 0.3 score SUBJ_ILLEGAL_CHARS 0 score RCVD_IN_NJABL_DUL 0.3 score ADDRESS_IN_SUBJECT 0.1 score HELO_LH_HOME 1.0 #internal_networks 192.168.XXX/24 trusted_networks 31.170.8.33 31.170.8.15 62.212.111.216 88.179.18.233 85.118.59.50 #score ALL_TRUSTED 0.3 score HELO_DYNAMIC_IPADDR 0.3 score FORGED_MUA_OUTLOOK 0.5 # Eudora sucks score EXTRA_MPART_TYPE 0.1 score MIME_BOUND_EQ_REL 0.1 score MIME_QP_LONG_LINE 0.1 # SMTP senders *have* dynamic IP addresses # A.B.C.D.dnsbl.sorbs.net -> 127.0.0.10 score RCVD_IN_DYNABLOCK 0 score HELO_DYNAMIC_IPADDR 0.3 score RCVD_IN_SORBS 0.1 score RCVD_IN_PBL 0.1 score RCVD_IN_SORBS_DUL 0 # old bug... score FH_DATE_PAST_20XX 0.0 ~~~ ### URIBL ~~~ header __RCVD_IN_HOSTKARMA eval:check_rbl('HOSTKARMA-lastexternal','hostkarma.junkemailfilter.com.') describe __RCVD_IN_HOSTKARMA Sender listed in JunkEmailFilter tflags __RCVD_IN_HOSTKARMA net header RCVD_IN_HOSTKARMA_W eval:check_rbl_sub('HOSTKARMA-lastexternal', '127.0.0.1') describe RCVD_IN_HOSTKARMA_W Sender listed in HOSTKARMA-WHITE tflags RCVD_IN_HOSTKARMA_W net nice score RCVD_IN_HOSTKARMA_W -5 header RCVD_IN_HOSTKARMA_BL eval:check_rbl_sub('HOSTKARMA-lastexternal', '127.0.0.2') describe RCVD_IN_HOSTKARMA_BL Sender listed in HOSTKARMA-BLACK tflags RCVD_IN_HOSTKARMA_BL net score RCVD_IN_HOSTKARMA_BL 3.0 header RCVD_IN_HOSTKARMA_BR eval:check_rbl_sub('HOSTKARMA-lastexternal', '127.0.0.4') describe RCVD_IN_HOSTKARMA_BR Sender listed in HOSTKARMA-BROWN tflags RCVD_IN_HOSTKARMA_BR net score RCVD_IN_HOSTKARMA_BR 2.0 ifplugin Mail::SpamAssassin::Plugin::URIDNSBL urirhssub URIBL_HOSTKARMA_BL hostkarma.junkemailfilter.com. A 127.0.0.2 describe URIBL_HOSTKARMA_BL Contains an URL listed in the URIBL HOSTKARMA blacklist body URIBL_HOSTKARMA_BL eval:check_uridnsbl('URIBL_HOSTKARMA_BL') tflags URIBL_HOSTKARMA_BL net score URIBL_HOSTKARMA_BL 3.0 urirhssub URIBL_HOSTKARMA_BR hostkarma.junkemailfilter.com. A 127.0.0.4 describe URIBL_HOSTKARMA_BL Contains an URL listed in the URIBL HOSTKARMA brownlist body URIBL_HOSTKARMA_BR eval:check_uridnsbl('URIBL_HOSTKARMA_BR') tflags URIBL_HOSTKARMA_BR net score URIBL_HOSTKARMA_BL 2.0 urirhssub URIBL_HOSTKARMA_FRESH_2D hostkarma.junkemailfilter.com. A 127.0.2.1 describe URIBL_HOSTKARMA_BL Contains an URL listed in the URIBL HOSTKARMA very young list body URIBL_HOSTKARMA_FRESH_2D eval:check_uridnsbl('URIBL_HOSTKARMA_FRESH_2D') tflags URIBL_HOSTKARMA_FRESH_2D net score URIBL_HOSTKARMA_FRESH_2D 2.0 urirhssub URIBL_HOSTKARMA_FRESH_10D hostkarma.junkemailfilter.com. A 127.0.2.2 describe URIBL_HOSTKARMA_BL Contains an URL listed in the URIBL HOSTKARMA young list body URIBL_HOSTKARMA_FRESH_10D eval:check_uridnsbl('URIBL_HOSTKARMA_FRESH_10D') tflags URIBL_HOSTKARMA_FRESH_10D net score URIBL_HOSTKARMA_FRESH_2D 1.0 ~~~ ### Howto écrire ses règles SpamAssassin TODO ### Whitelister/Blacklister un email ou un nom de domaine Par utilisateur (~/.spamassassin/user_prefs) ou global (/etc/spamassassin/local_evolix.cf) : ~~~ whitelist_from foo@bar.com whitelist_from *@evolix.fr blacklist_from pouet@camembert.com ~~~ ### AWL : AutoWhitelist SA a un puissant outil d'AWL si l'on définit bien une liste d'emails / expéditeurs avant de l'initialiser. Néanmoins, il faut le maintenir : Pour lister sa whitelist (couple email / 2 1er octets de l'IP) ~~~ # sa-awl /var/spool/spam/auto_whitelist AVG (TOTSCORE/COUNT) -- EMAIL|ip=IPBASE AVG est le score moyen TOTSCORE est le score total des mails COUNT est le nombre de mails ~~~ Pour supprimer les entrées "vues" moins de 2 fois : ~~~ # sa-awl --clean --min 2 /var/spool/spam/auto_whitelist ~~~ Pour supprimer des entrées particulières : ~~~ # spamassassin --remove-addr-from-whitelist=foo@bar SpamAssassin auto-whitelist: removing address: foo@bar ~~~ ## SpamHaus [SpamHaus](https://www.spamhaus.com/) propose un certains nombres d'outils pratiques pour l'antispam. Il s'agit principalement de données pour identifier les adresses IP ou noms de domaine problématiques. Une bonne partie des données sont gratuites via [SpamHaus.org](https://www.spamhaus.org/) : * [zen.spamhaus.org](https://www.spamhaus.org/zen/) : combinaisons de plusieurs DNSBL : SBL+CSS+XBL+PBL * [dbl.spamhaus.org](https://www.spamhaus.org/dbl/) : URIBL > Note : la gratuité est réservée à un usage non-commercial et pour un nombre de requêtes limité, cf les [Terms Of Use](https://www.spamhaus.org/organization/dnsblusage/). Si vous faites trop de requêtes, SpamHaus vous renverra [des codes 127.255.255.25X (rate-limiting)](https://www.spamhaus.org/news/article/807/using-our-public-mirrors-check-your-return-codes-now) et un commercial vous contactera ;) ### SpamHaus.org via Postfix `main.cf` : ~~~ smtpd_recipient_restrictions = [...] reject_rhsbl_sender dbl.spamhaus.org=127.0.1.[2..99], reject_rhsbl_helo dbl.spamhaus.org=127.0.1.[2..99], reject_rhsbl_reverse_client dbl.spamhaus.org=127.0.1.[2..99], reject_rbl_client zen.spamhaus.org=127.0.0.[2..255], warn_if_reject reject_rbl_client zen.spamhaus.org=127.255.255.[1..255], ~~~ ### DQS Il s'agit d'un service payant fourni par SpamHaus, mais sous certaines conditions vous pouvez [demander un accès gratuit](https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account/). Pour mieux comprendre, lisez ce [tableau comparatif](https://www.spamhaus.com/custom-content/uploads/2023/03/DQS-Legacy-DNSBL-comparison-table_D2.png) entre SpamHaus.org, DQS gratuit et DQS payant. Voici ce que propose DQS : * un accès plus rapide (temps réel et TTL à 1s) à la DNSBL Zen et l'URIBL DBL * un accès plus complet à la DNSBL SBL (inclus dans Zen) et l'URIBL DBL * un accès à l'URIBL ZRD pour les noms de domaine créés récemment * un accès à HBL (Hash Block List) pour bloquer des emails en fonction du contenu Cela s'utilise notamment via Postfix/Postscreen, Postfix ou SpamAssassin. ### DQS via Postscreen `main.cf` : ~~~ postscreen_dnsbl_sites = KEY.zen.dq.spamhaus.net=127.0.0.[2..255] postscreen_dnsbl_reply_map = texthash:/etc/postfix/dnsbl_reply ~~~ `dnsbl_reply` : ~~~ KEY.zen.dq.spamhaus.net zen.spamhaus.org ~~~ #### DQS via Postfix `main.cf` : ~~~ smtpd_recipient_restrictions = [...] reject_rhsbl_sender KEY.dbl.dq.spamhaus.net=127.0.1.[2..99], reject_rhsbl_helo KEY.dbl.dq.spamhaus.net=127.0.1.[2..99], reject_rhsbl_reverse_client KEY.dbl.dq.spamhaus.net=127.0.1.[2..99], reject_rhsbl_sender KEY.zrd.dq.spamhaus.net=127.0.2.[2..24], reject_rhsbl_helo KEY.zrd.dq.spamhaus.net=127.0.2.[2..24], reject_rhsbl_reverse_client KEY.zrd.dq.spamhaus.net=127.0.2.[2..24], reject_rbl_client KEY.zen.dq.spamhaus.net=127.0.0.[2..255] rbl_reply_maps = hash:/etc/postfix/dnsbl-reply-map ~~~ `dnsbl-reply-map` : ~~~ KEY.dbl.dq.spamhaus.net=127.0.1.[2..99] $rbl_code Service unavailable; $rbl_class [$rbl_what] blocked using private dbl.spamhaus.org${rbl_reason?; $rbl_reason} KEY.zrd.dq.spamhaus.net=127.0.2.[2..24] $rbl_code Service unavailable; $rbl_class [$rbl_what] blocked using private zrd.spamhaus.org${rbl_reason?; $rbl_reason} KEY.zen.dq.spamhaus.net=127.0.0.[2..255] $rbl_code Service unavailable; $rbl_class [$rbl_what] blocked using private zen.spamhaus.org${rbl_reason?; $rbl_reason} ~~~ #### DQS via SpamAssassin ~~~ $ git clone https://github.com/spamhaus/spamassassin-dqs $ sh hbltest.sh Please input your DQS key: KEY $ sed -i -e 's/your_DQS_key/KEY/g' sh.cf $ sed -i -e 's/your_DQS_key/KEY/g' sh_hbl.cf $ vim sh.pre # cp sh.cf /etc/spamassassin/ # cp sh_hbl.cf /etc/spamassassin/ # cp sh_hbl_scores.cf /etc/spamassassin/ # cp SH.pm /etc/spamassassin/ # cp sh_scores.cf /etc/spamassassin/ # cp sh.pre /etc/spamassassin/ ~~~ # ClamAV ### Constituer sa propre DB Le but est de créer une base de données contenant des signatures personnelles qui ne sont pas (encore) disponibles dans celles fournis par ClamAV. On va montrer un exemple pour identifier un virus en PJ de type facture.doc, qui contient une macro Word pour infecter des postes Windows. La pièce-jointe est identifiable sur VirusTotal : [[BR]] Elle n'est repéré que par 6 AV. Il est reconnu en tant que W97M/Downloader.akh. On va utiliser ce nom (+evolix) pour le mettre dans notre base de données. L'idée est d'identifier un endroit précis du fichier en utilisant par exemple hexdump : ~~~ 61 69 6e 2e 00 53 6f 63 6b 65 74 2e 43 10 6c 6f |ain..Socket.C.lo| ~~~ Et d'ajouter ces 16 octets en guise signature. ~~~ # echo "W97M/Downloader.akh+evolix:0:*:61696e2e00536f636b65742e43106c6f" >> /var/lib/clamav/evolix.ndb # chown clamav:clamav /var/lib/clamav/evolix.ndb ~~~ Dans le cas où il n'est pas évident de repérer une chaine précise on « fabriquera » une signature avec l'outil de ClamAV : sigtool. ~~~ # sig=$(cat facture.doc | sigtool --hex-dump | head -c 2048) # echo "NomDuVirus+evolix:0:*:$sig" >> /var/lib/clamav/evolix.ndb ~~~ On peut aussi tout simplement utiliser le checksum du virus (un sha256 par exemple). ~~~ # sigtool --sha256 facture.doc >> /var/lib/clamav/evolix.hsb ~~~ Dans certains cas, comme un fichier HTML « forgé bizarrement », ClamAV va d'abord décomposer le fichier HTML. Il faudra générer la signature à partir de l'extraction. ~~~ # clamscan --debug --leave-temp facture.doc > LibClamAV debug: cli_scanhtml: using tempdir /tmp/clamav-606ba4ba8c8504465cba15fc13c93942.tmp # cd /tmp/clamav-606ba4ba8c8504465cba15fc13c93942.tmp # sig=$(cat notags.html | sigtool --hex-dump | head -c 2048) # echo "NomDuVirus+evolix:0:*:$sig" >> /var/lib/clamav/evolix.ndb ~~~ Evolix tient une base de signatures pour ClamAV ### Bases officieuses #### Sanesecurity Sanesecurity contient de nombreuses bases de signatures de plus ou moins bonnes qualité : ~~~ $ rsync -avn rsync://rsync.sanesecurity.net/sanesecurity /tmp/sanesecurity/ ~~~ Un blog liste quelques signatures 0-day : #### Malwarepatrol ~~~ $ wget ~~~ Code XXXX à obtenir via inscription : (il existe aussi une version payante) #### SecuriteInfo inscription : (il existe aussi une version payante) #### Linux Malware Detect ~~~ $ wget ~~~ #### Yara Rules Nécessite ClamAV 0.99 (bêta) qui pourra utiliser le moteur Yara : ## FAQ ### Freshclam refuse de se mettre à jour Vérifier que votre pare-feu autorise `db.local.clamav.net` et `database.clamav.net` puis supprimer le fichier de mirroirs `/var/lib/clamav/mirrors.dat`. ### J'ai ajouté des CIDRs à une liste blanche mais elles ne semblent pas prises en compte Bien que la vérification de configuration ne signalera pas de probleme, mettre des CIDRs dans `/etc/postfix/client.access` ou `/etc/postfix/client.access_local` ne sera pas pris en compte car ce sont des tables de type `access(5)`. Pour specifierer des CIDRs il faut utiliser une table `cidr_table(5)` et verifier que l'option accepte ce genre de table ; `/etc/postfix/postscreen_access.cidr` est un fichier de ce type.