Exim4 で外部から postmaster@localhost に届いてしまう の履歴(No.1)

更新


公開メモ

観測された現象

IMAP の受信箱に妙なメールが届いた。

Return-path: <sender@example.com>
Envelope-to: postmaster@localhost
Received: from [107.172.77.101] (helo=inside)
	by my-server.com with esmtps  (TLS1.3) ...
	(envelope-from <sender@example.com>)
	for postmaster@localhost;

ABCD

本文は ABCD だけ。From: To: Subject: などのヘッダーもない。明らかに正規のメールではないが、SMTP セッションとしてはきちんと完了し、Exim4 が受け取って配送している。

ヘッダーから読み取れる経路

  • 接続元 107.172.77.101 は ColoCrossing(米国の VPS 業者)の IP
  • HELO は inside という嘘 FQDN
  • MAIL FROM:<sender@example.com>、RCPT TO:<postmaster@localhost> で通過
  • 認証なし(esmtps であって esmtpsa ではない)

exim4 -bt postmaster@localhost で配送経路を追うと:

R: system_aliases for postmaster@localhost
R: system_aliases for root@my-server.com
R: userforward for osamu@my-server.comt
...
osamu@my-server.com
    <-- root@my-server.com
    <-- postmaster@localhost

/etc/aliases の postmaster: root → root: osamu のチェーンで、外部から投げられた postmaster@localhost 宛のメールが自分の Maildir まで届いていた。

原因

ふたつの設定が組み合わさることで起きていた。

localhost が local_domains に入っている

exim4 -bP config | grep local_domains で確認:

domainlist local_domains = @:localhost:my-server.com

これは Debian Exim4 のデフォルトで、cron や mdadm からの root@localhost 宛通知がローカル配送されるために必要な設定。外すわけにはいかない。

Exim のデフォルト ACL に「postmaster は無条件で受け入れる」ルールがある

Debian の /etc/exim4/exim4.conf.template の acl_check_rcpt: セクションにこんなブロックがあった:

 # Accept mail to postmaster in any local domain, regardless of the source,
 # and without verifying the sender.
 accept
   local_parts = postmaster
   domains = +local_domains : +relay_to_domains

これは Exim の慣行で、「設定をミスっても postmaster だけは絶対に届くようにする」という保険。それ自体は妥当な思想だが、(1) と組み合わさると postmaster@localhost だけ外部から誰でも投げ込める入り口になってしまう。

bot の本来の狙いはおそらく次の段階の RCPT で外部リレーを試すことだったと思われる(relay_from_hosts には入っていないので拒否される)。今回は探査の ABCD だけが副産物として届いた格好。

対処方針

/etc/aliases のエイリアスチェーンを外すと cron 通知が届かなくなるので不可。local_domains から localhost を外すのも同じ理由で不可。

正しい対処は 「外部 IP から @localhost 宛の RCPT が来たら拒否する」を ACL で追加すること。「postmaster 無条件受け入れ」ルールよりも前に評価される位置に置く必要がある。

設定ファイルの特定

 $ sudo update-exim4.conf -v 2>&1 | head  using non-split configuration scheme from /etc/exim4/exim4.conf.template

split しない設定ファイルが使われていた。

ACL の追加

exim4.conf.template の acl_check_rcpt セクションに、accept hosts = :(非SMTP投入の素通し) の直後に次のように書いた:

acl_check_rcpt:
  # Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by
  # testing for an empty sending host field.
  accept
    hosts = :
    control = dkim_disable_verify

  ######### added from here on 2026-05-22
  # Deny external attempts to deliver to @localhost.
  # postmaster@localhost would otherwise be accepted by the unconditional
  # "accept postmaster" rule further down, since localhost is in
  # local_domains (required for cron/root mail to be delivered locally).
  deny
    message = relay not permitted: <$local_part@$domain> from remote host
    hosts = ! 127.0.0.0/8 : ! ::::1 : ! 172.16.0.0/12
    domains = localhost : localhost.localdomain
  ######### added until here on 2026-05-22

  # ... 既存の続き

更新&確認

$ sudo update-exim4.conf
$ sudo systemctl reload exim4
$ sudo exim4 -bh 107.172.77.101 <<'EOF'
EHLO inside
MAIL FROM:<sender@example.com>
RCPT TO:<postmaster@localhost>
QUIT
EOF

>>> check hosts = ! 127.0.0.0/8 : ! ::::1 : ! 172.16.0.0/12
>>> host in "..."? yes (end of list)
>>> check domains = localhost : localhost.localdomain
>>> localhost in "..."? yes (matched "localhost")
>>> deny: condition test succeeded
>>> end of ACL "acl_check_rcpt": DENY
550 relay not permitted: <postmaster@localhost> from remote host

ちゃんと拒否されるようになった。

注意:設定ファイルで ::1 と書くと動かない

コロン : は区切り文字として使われるので、::1 と書く代わりに ::::1 のように : を重ねて書かないとダメだった。はじめ、これで難儀した。

(NG)      hosts = ! 127.0.0.0/8 : ! ::::1 : ! 172.16.0.0/12
(OK)      hosts = ! 127.0.0.0/8 : ! ::1 : ! 172.16.0.0/12

コメント・質問





Counter: 64 (from 2010/06/03), today: 28, yesterday: 36