iptablesで特定ユーザ以外のSMTP通信をブロックし、SPAMの踏み台になるのを防ぐ方法
サーバに侵入されてしまった時、非常によくあるのが「SPAMの踏み台にされる」ことです。
運良く(運悪く?)SPAMをバラ撒いているプログラムを発見出来ればいいのですが、「SPAMの踏み台にされている疑いがある 1が、そのプログラムは特定出来ない」というのが一番嫌なケースかもしれません。
なぜこのようなことが起こるのかと言うと、次のような2つの問題があるからです。
1. すべてのユーザが外部のTCP 25番ポートに通信出来てしまう。
2. ユーザが外部と通信した時のログが残らない。
この2点を解決すれば、
1. PostfixやSendmailなどの、限られたMTAのみが外部のTCP 25番ポートと通信出来る。MTA経由でSPAMが送信されるリスクは残るが、ログは残るので追跡は可能になる。
2. ユーザが外部と通信したログが残れば、万が一SPAMをバラ撒くプログラムが存在した時に探す手掛りになる。
ということで、SPAMをバラ撒くリスクを減らしつつ、問題を特定する可能性を高くすることが出来ます。
Linuxの iptables では、
1. 特定のユーザからの通信のみを許可する
2. 通信のログを取る
の2点が可能なので、「MTA以外のプログラムが外部のTCP 25番ポートと通信するのをブロックし、ブロックした通信のログを取る」方法を解説します。
## 前提と環境
この記事は、CentOS の以下のバージョンで動作確認してあります。
* CentOS 5.11 (iptables v1.3.5)
* CentOS 6.6 (iptables v1.4.7)
また、MTAとしてはpostfixを想定します。
CentOS 7 の firewalld ですが、ちょっと調べた限りではユーザIDを元にフィルタリングをすることは出来ないようです。もし CentOS 7 でこの記事にある内容を実現するには、firewalld を無効化して iptables を使う必要があるかもしれませんが、この点は未検証です。
## iptablesの設定
### ユーザIDによるパケットのフィルタリング
ユーザIDを元にパケットのフィルタリングをするには、iptablesの “owner” モジュールを使います。
“owner” モジュールは下記のオプションを取り、ユーザID以外にもグループID、プロセスIDなどでパケットをフィルターすることが出来ます。
- –uid-owner userid
- 実効ユーザIDが userid であるプロセスが生成したパケットにマッチ
- –gid-owner groupid
- 実効グループIDが groupid であるプロセスが生成したパケットにマッチ
- –pid-owner processid
- プロセスIDが processid であるプロセスが生成したパケットにマッチ
- –sid-owner sessionid
- セッションIDが sessionid であるプロセスが生成したパケットにマッチ
- –cmd-owner name
- コマンド名が name であるプロセスが生成したパケットにマッチ
なお、CentOS 5 の iptables の man によると、userid と groupid はそれぞれユーザID、グループIDしか受け付けないように書かれていますが、ユーザ名、グループ名を指定しても動くようです。
また、CentOS 6 の iptables では、userid と groupid に範囲を指定することが出来ます。例えば、`–uid-owner 1000-9999` と指定すると、ユーザID 1000 のユーザからユーザID 9999のユーザまでにマッチします。
以上を考慮して、「postfixユーザが生成したパケットが外部のTCP 25番と通信するのを許可する」は、以下のようになります。
sudo iptables -A OUTPUT -p tcp -m tcp –dport 25 -m owner –uid-owner postfix -j ACCEPT
なお、”owner”モジュールは OUTPUTチェーンでしか使えません。
### ログの出力
ログを出力するには、”LOG”ターゲットを使います。LOGターゲットは以下のオプションを受け付けます。
- –log-level level
- ログレベル(syslogのログレベルと同じ)
- –log-prefix prefix
- ログメッセージの先頭に prefix を付ける
- –log-tcp-sequence
- TCP のシーケンス番号を出力
- –log-tcp-options
- TCP オプションを出力
- –log-ip-options
- IP オプションを出力
- –log-uid
- パケットを生成したプロセスのユーザIDを出力
iptablesの基本動作は「マッチするルールが存在したら、指定したターゲットに処理を移し、そのチェーンでの処理を終了する」なんですが、マッチしたルールのターゲットが “LOG” だった場合にはそのチェーンでの処理は続きます。従って、「マッチしたパケットのログを取得してから拒否する」という場合には、ログを出力させるルールの後に、「パケットをDROPまたはREJECTする」というルールを書く必要があります。
以上を考慮すると、「postfixユーザ以外が生成したTCP 25番宛のパケットのログを記録し、拒否する」というルールは以下のようになります。
sudo iptables -A OUTPUT -p tcp -m tcp –dport 25 -m state –state NEW -j LOG –log-uid
sudo iptables -A OUTPUT -p tcp -m tcp –dport 25 -j DROP
## 動作確認
以上で iptables の設定は完了ですが、次は期待した通りの動作をするかどうかを確認します。
### postfixユーザ以外が外部のTCP 25番ポートに通信出来ないことの確認
まず、サーバにログインしているユーザで外部のメールサーバと直接通信し、接続出来ないことを確認してみます。外部のサーバと通信するには、telnet または nc を使うと良いでしょう。
telnetの場合:
$ telnet mail.examples.jp 25
Trying ***.***.***.***…
ncの場合:
$ nc mail.examples.jp 25
(応答なし)
上記のように応答がなければ、iptablesの設定はちゃんと出来てると思って良いでしょう。
この場合、/var/log/messages に以下のようなログが残っていると思います。
Jan 2 16:00:49 hogehost kernel: IN= OUT=eth0 SRC=*.*.*.* DST=*.*.*.* LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=49812 DF PROTO=TCP SPT=58389 DPT=25 WINDOW=5840 RES=0x00 SYN URGP=0 UID=2000
逆に、以下のように応答が返って来る時は、どこか設定に失敗しています。
telnetの場合:
$ telnet mail.examples.jp 25
Trying ***.***.***.***…
Connected to mail.examples.jp (***.***.***.***)
Escape character is ‘^]’.
220 mail.examples.jp ESMTP Postfix
ncの場合:
$ nc mail.examples.jp 25
220 mail.examples.jp ESMTP Postfix
### postfix が外部のTCP 25番ポートと通信出来ていることの確認
次に、postfix が外部のTCP 25番ポートと通信出来ていることの確認です。これは postfix にメールを渡し、ログを確認して外部に送信出来ていることを確認すれば良いでしょう。
例えば mail コマンドを実行し、
$ echo test | mail fuga@examples.com
/var/log/maillog に以下のようなログが残っていれば送信に成功しています。
Jan 2 14:39:18 mail postfix/pickup[23828]: 74A7B4A0056: uid=2000 from=
Jan 2 14:39:18 mail postfix/cleanup[25450]: 74A7B4A0056: message-id=<20150102053918.74A7B4A0056@mail.examples.jp>
Jan 2 14:39:18 mail postfix/qmgr[2133]: 74A7B4A0056: from=
Jan 2 14:39:18 mail postfix/smtp[25452]: 74A7B4A0056: to=
Jan 2 14:39:18 mail postfix/qmgr[2133]: 74A7B4A0056: removed
## 設定の保存
動作確認が出来たら、iptablesの設定を保存します。デフォルトでは iptables の設定は保存されず、再起動時には変更が元に戻されてしまうので、忘れずに保存しておきましょう。 2
iptables の保存は以下のコマンドで出来ます。
$ /sbin/service iptables save
成功すると、設定が /etc/sysconfig/iptables に書かれるのでチェックします。
$ sudo cat /etc/sysconfig/iptables