目次

blacklistd

2024/07/02

筆者が管理してるメールサーバーのユーザーがパスワード抜かれてPhishing Mailを転送しそうになってた。88通。

from
抜かれた人のメールアドレス
to
docomoのmail address
Body
国税庁を騙ったフィッシングメール

顛末

  1. パスワード抜かれた人から、「送ってもいない携帯キャリア宛メール」が配送されなかったエラーが大量に来る、と報告される
  2. 外出してて、友達と晩飯食ってる最中だったので、logの解析すらできず、取り急ぎ、smtpサーバー止める。結果的に4時間smtpサーバー止めた
  3. 帰宅して解析開始。この段階でspamの配信元になりそうになってたことに気づき焦ったが、全てError Mailになっていたことに気づき、ちょっと安心
    • 結局、このエラーメールを送信するちょっと(大体3時間程度)前にパスワードが破られたことが判明
  4. logから、SMTP AUTHで使われる「メールアドレスとパスワード」が抜かれて、SPAMを転送としようとしていることが判明。パスワードを強制変更
  5. SMTP AUTHの認証を確認してSMTPサーバー復旧

今回は「転送失敗」メールが88件、転送成功メールは0件で、他人に被害出さなくて済んだから良かったけどちょっと怖い思いをした。なお、転送に失敗していたのは、受信側の「携帯キャリア」のMail ServerがSMTPUTF8拡張をサポートしていなかったからだった。正直運良く転送されなかっただけで、一歩間違えたら大惨事(88通は決して少なくない)だった。

というわけで、せめてもの被害軽減策としてblacklistdを導入して、SMTPAUTHとIMAPへの接続を監視し、パスワードチェック攻撃を少しでもreduceしようとしてみた。パスワード破られたら、DKIMもDMARKもSPFも関係なく全部送れてしまうわけで…

なお、新しいパスワードは、強制的に16桁にしたから、しばらくは大丈夫。大丈夫だと思う。大丈であって欲しい。 (元のパスワード、6桁だったらしい。よく10年以上抜かれなかったなぁ…)

(Event Driven…)

問題と事前考察

根本的には、

という考察をした。もちろん、blacklistdで対応できる範囲はそれほど大きくないが、それでも何もしないよりは大きく改善することが期待できる。

blacklistdの導入

FreeBSDだと、portsを使ってPostfixをCompileして導入すればblacklistdに対応できる。Option設定画面でblacklistdをOnにしておくこと。

あとは、SMTP関連の設定だが、これはあまりにも重い話なので割愛。

blacklistdへの対応済みpostfixをblacklistdが動いていない状況で稼働させると、認証失敗時に/var/log/debug.log

Jun  9 15:11:24 mta postfix/smtpd[95847]: bl_init: connect failed for `/var/run/blacklistd.sock' (No such file or directory)

のようにErrorが記載される。(logファイルが /var/log/debug.logになるかどうかはsyslogdの設定に依存する)

この状態で、blacklistd及びpfの設定を行う。

pfの設定

本記事においては、

というポリシーでpf(Firewall)を設定する。

当然、自分の環境に合わせてしっかり確認してください。違いはせいぜい、pfのfilter ruleくらいしかないでしょう。

と言うわけで、Configは以下の通り。

pf.conf
##############################################################################
# pf.conf for mta
##############################################################################

##### Macros
# Interfaces
IFextn="xn1"

##### Tables

table <rfc1918> const { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7 }
table <rfc6890> const { 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 2001:0db8::/32 }
table <rfc6598> const { 100.64.0.0/10 }         # ISP CGN
# need to create /etc/pf.rej (Empty file permitted)
table <reject> persist file "/etc/pf.rej"

##### pf Options
set block-policy drop

##### Normarization
scrub in on $IFextn random-id fragment reassemble
scrub    on $IFextn random-id

##### Filtering ruleset
set skip on lo0

pass all
anchor "blacklistd/*" in on $IFextn

ポイントは、最後にあるanchor “blacklistd/*” in on $IFextnである。 この行が意味するのは、

ということになる。

pfの起動

ここまで設定したら、/etc/rc.confに

# pf
pf_enable="YES"
pflog_enable="YES"

を記載し、service pf start && service pflog startを実行する。

blacklistdの設定

blacklistdの設定は、rc.confで設定するblacklistd_flagsに設定された引数と/etc/blacklistd.confによって行う。 このほかに、

というファイルが利用される。

以下、blacklistd.confのサンプル

# $FreeBSD$
#
# Blacklist rule
# adr/mask:port type    proto   owner           name    nfail   disable
[local]
ssh             stream  *       *               *       3       24h
smtp            stream  *       *               *       3       24h
smtps           stream  *       *               *       3       24h
submission      stream  *       *               *       3       24h
imaps           stream  *       *               *       3       24h
*               *       *       *               *       3       60

# WhiteLists
# adr/mask:port type    proto   owner   name    nfail   disable
[remote]
# Never block localhost
127.0.0.1/32    *       *       *               *       *       *
[::1]/128       *       *       *               *       *       *

blacklistdの起動

ここまで設定が終わったら、Blacklistdを起動する。

blacklistdに関連するpfctlのコマンド

おまけ

sshdでもblacklistd対応

これでsshdもblacklistd対応になる。

Signal

  • Debug Levelを変化させる方法
    • blacklistdに対して SIG_USR1を送りつけると、debugレベルが上がる
    • blacklistdに対して SIG_USR2を送りつけると、debugレベルが下がる
  • 設定を再読み込みさせる方法
    • blacklistdに対して、SIG_HUPを送りつける
  • 終了させる方法
    • blacklistdに対して、SIG_KILL / SIG_INT / SIGTERMを送りつける

落穂拾い

name

nameフィールドは、使用するパケットフィルタールールの名前である。

名前が “-” で始まる場合、デフォルトのルール名がその名前の前に付加される。

名前に “/” が含まれる場合、名前の残りの部分はルールで指定されたアドレスに適用されるマスクとして解釈され、1つのルール違反で設定されたプレフィックス全体のサブネットがブロックされる

nameに/29と書くと、そのRuleでMatchしたSrcAddressに対して/29のNetmaskを付加した上で、その範囲のアドレスがBlockされるという挙動になる。

disable / duration

このフィールドには 最後のアクセスからブロッキングルールが有効であるべき時間を指定する。デフォルトは “” で、これは「永久に」を意味する。disableのデフォルト単位は秒だが、異なる単位を示す接尾辞を指定することができる。例えば、“m” は分、“h” は時間、“d” は日を表す。

source codeを読む限り、このフィールドに、例えば1d12h30m59sのように指定できるように見える。こう指定した場合、一度drop listに入ったら、1日12時間30分59秒の間Blacklistに登録される(すなわち、pfのdropテーブルに載り、filterout される)ように見える。

また、Source codeとdebug logを見る限り、Disable / Durationフィールドの値は以下のような動作に利用されるように見える。

  1. ApplicationがblacklistdにAddressを送る→Blacklist候補としてアドレスとポート番号を登録し、LastAccessを現在の時刻として登録する
  2. Blacklistdは -tで指定された値(もしくは15秒、もしくはdebugの値によっては5秒)ごとに、データをDBに同期する
    • 現在の時刻からLastAccessを引いて、その値が0以下になったらBlacklistから当該アドレスを削除する
    • この時、もし当該アドレスがFirewallのFilterout tableに登録されているなら、Filterout tableから当該アドレスを削除する
  3. もし、durationが来る前にApplicationがblacklistdにAddressを送ったら、LastAccessを現在の時刻に置き換え、nfailを増やす
  • もし、nfailがConfigurationで指定されている値以上になったら、-Cで指定されたアプリケーション(もしくはdefaultのblacklistd-helper)を呼び出し、Firewallにfilter設定を追加する)

したがって、disable/Durationの値は慎重に検討する必要がある。これを短くとるか長く取るかで、利便性と件出力のバランスを取る必要がある。

自分の接続元IPアドレスがblacklistに登録された

現在 blocklistctl には登録されているアドレスを削除する機能が無い。(というよりdumpしかできない) したがって、pfctl -a * -t port25 -T delete [Address]を実行して、一時的にTableから削除する必要がある。

なお拒否期限までの時間が残ってる間は blacklistd を再起動する度にpfに登録される

どうやって過去のAddressデータを保存しているのか?

blacklistdは、/var/db/blacklistd.dbにデータを記録している。このdbに記載されたデータをblacklistd起動時に読み出してpfに登録している。

このblacklistd.dbはBerklay DBファイルで、blacklistctl dump -aでDataをdump できる。

blacklistdのデータを複数台で共有

Blacklistdは、sourcecodeを見る限り、DBファイルに対してLockなどの操作を行っていないように見える。 したがって、これを見る限りでは、このDBのデータファイルを複数台のマシンで共有すると、Dataを破損する可能性があると考えられる。

末尾に追加でおまけ

本文中におまけはあるんだけど、こっちにやられた時の顛末とかのおまけを記載します。

解析した内容

全てはmaillogからの解析。

という挙動だった

雑感

今回は、送付先のメールサーバーがSMTPUTF8受け付けなかったからエラーメールになって帰ってきて、だから気づけたけど、はっきり言って、これは運がよかっただけ。 転送失敗してなかったら気づかなかったまであるわけで。

問題は、

というあたりにある。

結局、DKIMやDMARC、SPFは、いわゆるOpenRelayに近いメールへの対策としてはそれなりに効果はあるんだろうけど、パスワード抜かれたら終わりというのは変わらない。まぁ、パスワード認証を利用する限りそうなるのは自明なんだけど…。SMTP捨てられればいいんだけど、なかなかそういうわけにも行かないし。

パスワード認証の代わりに個人証明書を使うといのはないわけじゃない。設定や利用に関しては、まぁ、面倒なだけでやれなくはないし。 ただ、この手を採用した場合の問題は、「個人証明書の発行」にある。 今時オレオレ証明書ってのは面倒が過ぎる(client側の設定も鯖側の設定も面倒)だし、自分がsubsidiary CAになるのは大変が過ぎるし… でもまぁ、いうて、弱いパスワードが何よりも悪いのは事実だな。こいつをまず何とかするか。

ちょっとだけ愚痴

今回blacklistdを導入するにあたって、pfで対応するサンプルが非常に少なかった。なので、結局source codeまで見ないとわからないところがたくさんあった。

FreeBSDにおけるFirewall実装を選ぶなら、スピードの点でipfwが一番良い。特にCiscoとかの昔ながらRouterでFirewall設定したことがある人はipfwの方がわかりやすいとおもう。ただ、筆者は今時のPacket Filter Firewallでは設定はある程度抽象化されていて欲しい。その意味で、OpenBSD由来のpfは非常に気に入っている。

ただ、FreeBSDに移植されているpfは、OpenBSDのpfよりも常に古いのがやはり辛い。NAT64はOpenBSDならpfでできるんだけど、FreeBSDだとipfwでやるしか今のところないし。

うーん、やっぱり色々難しいなぁ…