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
This commit is contained in:
Cédrix 2026-09-29 08:40:43 +02:00
parent b7c05a6feb
commit 4d8dee3ecf
2 changed files with 203 additions and 0 deletions

View file

@ -174,6 +174,7 @@ OVH, sinon il décrit un état qui n'existe plus.
| Document | Sujet |
|---|---|
| [`docs/courrier-sortant.md`](docs/courrier-sortant.md) | relais, SPF/DKIM/DMARC, plafonds, boîtes du service |
| [`docs/courrier-entrant.md`](docs/courrier-entrant.md) | usurpation du domaine, liste blanche postmaster d'ISPConfig, tri dans Junk |
| [`docs/certificats.md`](docs/certificats.md) | les deux mécanismes TLS, leurs pièges, les réparations |
| [`docs/sauvegardes.md`](docs/sauvegardes.md) | sauvegarder les bases, et surtout les restaurer |
@ -206,6 +207,17 @@ les pièges qui vont avec :
---
## Courrier entrant
Un message qui se fait passer pour `@alpinux.org` doit être refusé ou rangé
dans `Junk`. Le 28/09/2026, un phishing usurpant `postmaster@` est passé sans
aucun contrôle, à cause d'une liste blanche posée par ISPConfig. Les trois
protections mises en place, et comment les vérifier :
→ **[`docs/courrier-entrant.md`](docs/courrier-entrant.md)**
---
## Certificats TLS
Deux mécanismes coexistent — un certificat certbot multi-domaines pour huit

191
docs/courrier-entrant.md Normal file
View file

@ -0,0 +1,191 @@
# 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`](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` :
```diff
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
```sh
# 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
```sh
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.