フルポートスキャンから開放ポートを隠す方法
フルポートスキャンされた場合でも、全ての開放ポートを特定されない方法とその原理のメモです。
※今回はTCPに限定しています。
隠す方法
iptablesのlimitモジュールを使います。(細かな説明などは後述)
iptables -P INPUT DROP iptables -N LIMIT iptables -t filter -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT iptables -t filter -A INPUT -p tcp --syn -m limit --limit 10/m --limit-burst 10 -j LIMIT iptables -t filter -A LIMIT -p tcp --dport-j ACCEPT
本当に隠せているか試してみる
検証環境(サーバ側)はDebianを用意して22/ssh, 80/http, 443/httpsを動かしてみました。
root@debian:~# lsb_release -a No LSB modules are available. Distributor ID: Debian Description: Debian GNU/Linux 7.8 (wheezy) Release: 7.8 Codename: wheezy root@debian:~# netstat -nltp 稼働中のインターネット接続 (サーバのみ) Proto 受信-Q 送信-Q 内部アドレス 外部アドレス 状態 PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 32519/apache2 tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 32341/sshd tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 32519/apache2
フィルタを設定してみます。
root@debian:~# cat hidden.iptables.sh #!/bin/sh iptables -F iptables -X iptables -Z iptables -P INPUT DROP iptables -P OUTPUT ACCEPT iptables -P FORWARD DROP iptables -N LIMIT iptables -t filter -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT iptables -t filter -A INPUT -p tcp --syn -m limit --limit 10/m --limit-burst 10 -j LIMIT iptables -t filter -A LIMIT -p tcp --dport 22 -j ACCEPT iptables -t filter -A LIMIT -p tcp --dport 80 -j ACCEPT iptables -t filter -A LIMIT -p tcp --dport 443 -j ACCEPT iptables -nvL -t filter root@debian:~# ./hidden.iptables.sh Chain INPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED 0 0 LIMIT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcpflags: 0x17/0x02 limit: avg 10/min burst 10 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain LIMIT (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
OUTPUTのポリシーがACCEPTだったりするのはオッカムの剃刀でそぎ落とされたためです。
ポートスキャンをかける前に一般ユーザがサービスにアクセスできることを確認しておきます。
% nc -nv 192.168.11.102 22 (UNKNOWN) [192.168.11.102] 22 (ssh) open SSH-2.0-OpenSSH_6.0p1 Debian-4+deb7u2 ^C % nc -nv 192.168.11.102 80 (UNKNOWN) [192.168.11.102] 80 (http) open ^C % nc -nv 192.168.11.102 443 (UNKNOWN) [192.168.11.102] 443 (https) open ^C
では、攻撃者視点からポートスキャンを実施してみます。
root@kali:~# nmap -n -r -sS -p 1-65535 192.168.11.102 Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-14 05:15 CST Nmap scan report for 192.168.11.102 Host is up (0.00028s latency). All 65535 scanned ports on 192.168.11.102 are filtered MAC Address: 00:0C:29:3B:B9:76 (VMware) Nmap done: 1 IP address (1 host up) scanned in 1371.88 seconds
65535ポートすべてフィルタされていると判定されました。(こうなるように設定したフィルタだから当然なのですが...)
原理
今回、検証用に書いたフィルタはlimitモジュールを使用して1分あたり10個以上のsynパケットを受け取ると11個目以降のパケットを全てDROPします。
iptables -P INPUT DROP iptables -t filter -A INPUT -p tcp --syn -m limit --limit 10/m --limit-burst 10 -j LIMIT
limitモジュールの説明 Linux 2.4 Packet Filtering HOWTO: Using iptables
簡単な説明 書式 : -m limit --limit Rate --limit-burst Max Maxサイズのバッファからあふれたものは判定しない。 Rateで指定したサイズ/単位時間ごとにバッファをクリアする。
上記の検証では、わざとnmapに-rオプション*1を使用しました。つまり、1番から10番までのTCPポートは開放確認されますが、その後は1分経過するまで、synパケットがDROPされるので、その間に22や80を過ぎると開放ポートの見逃しが発生します。
当然、値は各サイトやサービスごとに調整が必要です。
また、問題点もあります。このルールを適用してポートスキャンをされている間は正規のユーザがsshで接続しようとしても、synパケットがDROPされて、接続できません。そこで、hashlimitモジュールを使えば、送信元IPアドレスごとにフィルタされるので、正規のユーザのアクセスに影響を与えることがありません。
hashlimitモジュールの説明 Man page of iptables-extensions
どうやって隠されたポートを発見するか(攻撃者視点)
- well knownでbindしているサービスは見つけられる可能性が高い(nmapの-Fオプション*2 )
root@kali:~# nmap -n -sS -F 192.168.11.102 Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-14 05:56 CST Nmap scan report for 192.168.11.102 Host is up (0.00024s latency). Not shown: 98 filtered ports PORT STATE SERVICE 80/tcp open http 443/tcp open https MAC Address: 00:0C:29:3B:B9:76 (VMware) Nmap done: 1 IP address (1 host up) scanned in 19.01 seconds
- 時間的な制約がなければ、スキャンタイミングをゆっくり(nmapの-Tオプション)
root@kali:~# nmap -n -sS -F -T1 192.168.11.102 Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-14 06:32 CST Nmap scan report for 192.168.11.102 Host is up (0.00066s latency). Not shown: 97 filtered ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 443/tcp open https MAC Address: 00:0C:29:3B:B9:76 (VMware) Nmap done: 1 IP address (1 host up) scanned in 3275.71 seconds
およそ目安(initial_rtt_timeoutの値) T0 : 5min (serial) T1 : 15sec (serial) T2 : 1sec (serial) T3 : 1sec (parallel) T4 : 500msec (parallel) T5 : 250msec (parallel)
まとめ
limitモジュールはDoSの対策に使われるのが一般的だと思いますが、少し変わった用途を考えてみました。
ハイポートで開放しているポートを隠すのには有効だと思います。
「もっとこうした方がいい」、「こんな場合、問題あるよね」などツッコミあれば連絡いただけると幸いです。