alpinux-owni/docs/courrier-entrant.md
Cédrix 4d8dee3ecf Documenter le courrier entrant : l'usurpation de postmaster@
Un phishing daté du 28/09 usurpait postmaster@ et est passé sans aucun
contrôle : la liste blanche que l'installeur d'ISPConfig pose sur
postmaster/hostmaster/abuse (want_spam) coupe SPF et DMARC. Le document
décrit les trois protections mises en place, comment les vérifier, et
ce qu'elles laissent de côté.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdfUCdensc9bEAtnNvQmS2
2026-09-29 08:40:43 +02:00

7.3 KiB

Courrier entrant d'owni : l'usurpation du domaine

Comment owni refuse un message qui se fait passer pour @alpinux.org, et pourquoi postmaster@ était la seule adresse qu'on pouvait usurper sans aucun contrôle. Le pendant sortant est courrier-sortant.md.

État au 29/09/2026.

L'incident du 28/09/2026

Un phishing (« Modification d'un e-mail envoyé », lien vers *.web.core.windows.net) est arrivé dans la boîte postmaster@, avec From: et To: tous deux à postmaster@alpinux.org. Il ne portait aucun en-tête X-Spam-* ni Authentication-Results.

Received: from [171.249.196.126] (unknown [171.249.196.126])
    by owni.alpinux.org (Postfix) with ESMTP id 79115207A0

L'expéditeur était une ADSL Viettel, qui s'est connectée directement au port 25, sans authentification. Pourtant, le SPF -all et le DMARC p=quarantine du domaine auraient suffi à l'arrêter. Aucun des deux n'a été consulté.

Pourquoi il est passé

Postfix l'a accepté. Le destinataire est local, et l'expéditeur postmaster@ existe, donc reject_unlisted_sender le laisse passer. Il n'y avait pas de reject_sender_login_mismatch. Et même activé, celui-ci n'aurait rien vu : la boîte postmaster@ a le SMTP désactivé (mail_user.disablesmtp = 'y'), elle est donc absente de smtpd_sender_login_maps.

rspamd ne l'a pas analysé. Dans /var/log/rspamd/rspamd.log :

apply static settings whitelist; rcpt matched; priority high
task is whitelisted
(default: S (no action): [0.00/15.00] []) ... settings_id: whitelist

L'installeur d'ISPConfig écrit dans /etc/rspamd/local.d/users.conf :

whitelist {
    priority = 5;
    rcpt = "postmaster"; rcpt = "hostmaster"; rcpt = "abuse";
    want_spam = yes;
}

L'intention est bonne : la RFC 2142 veut que ces adresses reçoivent toujours les plaintes. Mais want_spam = yes coupe toutes les vérifications, SPF et DMARC compris, pour tout ce qui leur est adressé.

Les trois protections en place

1. rspamd : liste noire sur l'enveloppe (interface ISPConfig)

Dans Email → Spamfilter → Blacklist, deux entrées : postmaster@alpinux.org et abuse@alpinux.org (table spamfilter_wblist).

ISPConfig génère /etc/rspamd/local.d/users/spamfilter_wblist_N.conf : si l'expéditeur d'enveloppe est cette adresse et le destinataire @alpinux.org, alors reject = 0.2. La priorité (50) l'emporte sur la liste blanche (5).

À ne pas confondre avec Email → Global Filters → Blacklist, qui alimente la table Postfix mail_access. Celle-ci est lue avant permit_sasl_authenticated : un expéditeur ajouté là serait refusé même authentifié.

2. Postfix : expéditeur local ⇒ authentification (interface ISPConfig)

Dans System → Server Config → owni → Mail, l'option « Reject sender and recipient login mismatch » est cochée. ISPConfig réécrit alors :

smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch,
    permit_mynetworks,
    check_sender_access proxy:mysql:/etc/postfix/mysql-virtual_sender.cf,
    reject_sender_login_mismatch, permit_sasl_authenticated,
    reject_non_fqdn_sender, reject_unlisted_sender
  • Un client non authentifié qui envoie avec une boîte existante (SMTP activé) est refusé.
  • Un client authentifié ne peut envoyer qu'avec sa propre adresse, ou avec un alias marqué « Allow send as ».

Avant d'activer l'option, j'ai vérifié sur 3 jours de logs que tous les envois SASL utilisaient leur propre adresse (git_app.noreply, alpid.noreply). localhost envoie avec alpinux@ et secretaire@, mais passe par permit_mynetworks.

3. rspamd : analyser sans jamais rejeter (fichier, hors interface)

want_spam = yes est remplacé dans /etc/rspamd/local.d/users.conf :

 		rcpt = "abuse";
-		want_spam = yes;
+		# Plus de want_spam : on analyse (SPF/DMARC), on ne rejette jamais (RFC 2142)
+		apply {
+			actions {
+				reject = null;
+				greylist = null;
+			}
+		}

L'ancien fichier est sauvegardé dans users.conf.bak-20260929. Pour que la correction survive à une mise à jour d'ISPConfig, une copie est placée dans /usr/local/ispconfig/server/conf-custom/install/rspamd_users.conf.master.

Pourquoi pas « destination locale ⇒ authentification »

Ce serait refuser toute la réception : le port 25 est le MX, et aucun serveur extérieur (Gmail, Orange, les listes) ne s'y authentifie. La règle porte sur l'expéditeur local (protection 2).

Celle-ci ne suffit pas seule : elle lit l'enveloppe (MAIL FROM), pas l'en-tête From:. Un MAIL FROM:<x@bidon.ru> accompagné de From: postmaster@alpinux.org passe Postfix. C'est DMARC, dans rspamd, qui l'arrête, et il ne le peut que si la liste blanche ne l'en empêche pas (protection 3).

Où finit le spam de postmaster@

Dans Junk. La chaîne :

  1. rspamd, via milter_headers, pose X-Spam: Yes et X-Spam-Status: Yes, score=….
  2. Dovecot exécute sieve_before = /var/vmail/%d/%n/.ispconfig-before.sieve, généré par ISPConfig parce que mail_user.move_junk = 'y' : if header :matches "X-Spam-Status" "Yes, *" { fileinto :create "Junk"; stop; }
  3. En secours, sieve_before2 = /var/lib/dovecot/sieve/spam-to-junk.sieve fait la même chose.

La relève de la messagerie lit INBOX,Junk (IMAP_PM_DOSSIER) : un rapport DMARC classé à tort reste donc traité.

Vérifier

# Rejouer une usurpation dans rspamd, depuis l'IP de l'attaquant
rspamc -h localhost:11333 -i 171.249.196.126 \
  -F <enveloppe> -r <destinataire> < test.eml

# Le tri sieve, à sec, sur une copie du script et un maildir jetable
# ($W doit être lisible par vmail ; -u postmaster@… échoue sur l'auth)
rspamc -h localhost:11333 --mime -i 171.249.196.126 -F bidon@example.ru \
  -r postmaster@alpinux.org < test.eml > $W/out.eml
sudo sieve-test -o mail_uid=vmail -o mail_gid=vmail \
  -o mail_location=maildir:$W/md $W/before.sieve $W/out.eml

# Un utilisateur qui envoie avec une adresse qui n'est pas la sienne
sudo grep "not owned by user" /var/log/mail.log

Résultats relevés le 29/09/2026 :

Scénario Avant Après
Enveloppe et From: = postmaster@, vers postmaster@ accepté, 0.00 rejeté
Enveloppe bidon, From: = postmaster@, vers postmaster@ accepté, 0.00 Junk, 17.80 (SPF, DMARC)
Même chose vers president@ rejeté rejeté
Rapport externe légitime vers postmaster@ accepté accepté, -0.40

Pièges

  • Un refus not owned by user : quelqu'un envoie avec un alias sans « Allow send as ». Cocher la case sur l'alias dans ISPConfig ; ne pas décocher l'option globale.
  • Après une mise à jour d'ISPConfig, vérifier que users.conf n'a pas retrouvé want_spam : la copie dans conf-custom/install/ doit l'éviter.
  • Les boîtes au SMTP désactivé et les redirections sans « Allow send as » (abuse@, kernel@, cedric.a5l@) ne sont pas couvertes par la protection 2. Seuls DMARC et, pour abuse@, la liste noire les protègent.

Retour arrière

sudo cp -a /etc/rspamd/local.d/users.conf.bak-20260929 /etc/rspamd/local.d/users.conf
sudo rm /usr/local/ispconfig/server/conf-custom/install/rspamd_users.conf.master
sudo systemctl reload rspamd

Les protections 1 et 2 s'annulent depuis l'interface ISPConfig.