著者: | 佐藤裕介 (nuts@cclub.cc.tut.ac.jp) |
---|---|
バージョン: | 2005/11/18 01:00:00 +0900 (JST) |
このドキュメントでは、 ipt_recent モジュールの機能を利用して ssh の brute force attack に対抗する方法を示します。具体的には、あるホストが、 一定時間内に一定回数 ssh でのログインに失敗したら、そのホストからのアク セスを一定時間遮断する、という方法をとります [1] 。
[1] | もっとも、見ているのはトランスポート層だけなので、本当に SSH で ログインしようとしているのか、は判断していません。 |
このドキュメントでは、次のことは分かっているものとして話を進めます。
最近、私の管理しているホストに向けて行われた攻撃のログ (/var/log/secure on Vine Linux 2.6r4) です。このように、ユーザ名とパスワードの組み合わ せを自動で生成するなり何なりして、それを片っ端から試す攻撃方法を brute force attack (力ずく攻撃・総当り攻撃)と言います [2] 。
Oct 26 04:07:06 debonair sshd[18883]: Illegal user b from 210.98.138.250 Oct 26 04:07:08 debonair sshd[18883]: Failed password for illegal user b from 210.98.138.250 port 59480 ssh2 Oct 26 04:07:09 debonair sshd[18885]: Illegal user c from 210.98.138.250 Oct 26 04:07:11 debonair sshd[18885]: Failed password for illegal user c from 210.98.138.250 port 59733 ssh2 Oct 26 04:07:12 debonair sshd[18887]: Illegal user d from 210.98.138.250 Oct 26 04:07:14 debonair sshd[18887]: Failed password for illegal user d from 210.98.138.250 port 59983 ssh2 Oct 26 04:07:15 debonair sshd[18889]: Illegal user e from 210.98.138.250 Oct 26 04:07:17 debonair sshd[18889]: Failed password for illegal user e from 210.98.138.250 port 60228 ssh2
[2] | この例は a~z, aa~zz, aaa~zzz ……というユーザ名とパスワード の組み合わせを順に試しています。 なお、本ドキュメントの対策は brute force attack 以外の類似の方 法(辞書式攻撃など)にも有効です。 |
ipt_recent とは、 iptables で ''-m recent'' というオプションを使えるよ うにするモジュールです。このオプションを指定すると、次のような機能を使 うことができます。
今回は、 ipt_recent モジュールの機能 [3] を使って「n 回以上攻撃を試行 したらアクセス禁止」という処理を実装し、 brute force attack に対抗しま す。
[3] | IP アドレスを記録するリストはいくつでも作れるので「このプロトコ ルならこのリスト」等の処理が可能です。 また、リストにはパケットの source IP アドレスに加えてタイムスタ ンプも記録されるので、「直近 n 秒の間に記録があったら」や「n 回 以上記録があったら」といった条件も指定できます。 |
参考のために、 Fabrice MARIE 氏の Netfilter Extensions HOWTO より 3.16 recent patch の訳を以下に挙げておきます。
Stephen Frost <sfrost@snowman.net> によるパッチです。これを使うと、 IP アドレスのリストを動的に作成することができます。また、そのリスト とのマッチをとることもできます(マッチの方法はいくつかあります)。
例えば、ファイアウォールの port 139 にアクセスしようとしてきた輩を 'badguy' というリストにして、以降そこからのパケットを何も考えずに DROP する、とかいうことができます。
# iptables -A FORWARD -m recent --name badguy --rcheck --seconds 60 -j DROP # iptables -A FORWARD -p tcp -i eth0 --dport 139 -m recent --name badguy --set -j DROP # iptables --list Chain FORWARD (policy ACCEPT) target prot opt source destination DROP all -- anywhere anywhere recent: CHECK seconds: 60 DROP tcp -- anywhere anywhere tcp dpt:netbios-ssn recent: SET
recent マッチで使えるオプションは :
簡単なものとして、 60 秒間に 5 回までしかログインを試行できないように する、という方法を試してみましょう。60 秒間に 5 回ログインを試行すると それ以降はしばらくログイン試行が失敗するようになり、最初のアクセスから 60 秒経過すると 6 回目のログイン試行ができるようになります。
$IPTABLES -A INPUT -p tcp --syn --dport 22 -m recent --name sshattack --set $IPTABLES -A INPUT -p tcp --syn --dport 22 -m recent --name sshattack --rcheck --seconds 60 --hitcount 5 -j LOG --log-prefix 'SSH attack: ' $IPTABLES -A INPUT -p tcp --syn --dport 22 -m recent --name sshattack --rcheck --seconds 60 --hitcount 5 -j DROP
それぞれのルールの意味は次のようなものです。
ここでは例を簡単にするために INPUT チェインに直接ルールを追加していま す。フィルタリングルールのメンテナンスを容易にしたければ、新しくチェイ ンを作って(例えば $IPTABLES -N ssh )そこにルールを追加し、 ssh のパケットをそのチェインに通すようにした方が見通しがいいでしょう。
この例は次のメーリングリストへの投稿を参考にしました。 http://lists.suse.com/archive/suse-security/2005-Feb/0024.html
もう少し複雑なものでは、 60 秒間に 5 回以上ログインを試行したら、以降 10 分間はアクセス禁止、という処理も可能です。
$IPTABLES -N SSH-evil $IPTABLES -A SSH-evil -m recent --name badSSH --set -j LOG --log-level DEBUG --log-prefix "evil SSH user: " $IPTABLES -A SSH-evil -j REJECT $IPTABLES -A SSH -p tcp ! --syn -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -N SSH $IPTABLES -A SSH -p tcp --syn -m recent --name badSSH --rcheck --seconds 600 -j REJECT $IPTABLES -A SSH -p tcp --syn -m recent --name sshconn --rcheck --seconds 60 --hitcount 5 -j SSH-evil $IPTABLES -A SSH -p tcp --syn -m recent --name sshconn --set $IPTABLES -A SSH -p tcp --syn -j ACCEPT
SSH-evil チェインと SSH チェインがありますが、先に SSH チェインに目を 通して下さい。 SSH チェインには、 -p tcp --dport ssh にマッチしたパ ケットが入ってくるようにします [4] 。
IP アドレスのリストとして sshconn と badSSH の 2 つを使っています。役割 は次の通りです。
それぞれのルールの意味は次のようなものです。
まず、 SYN フラグの立っていないパケットは ACCEPT します。
brute force attack 攻撃元ホストからのパケットを REJECT します。
具体的には、「これは brute force attack だ」という判定が、ここ 10 分以内になされているホストからのパケットだった場合、 REJECT しま す。
brute force attack が行われているかどうかの判定です。
具体的には、パケットの source IP アドレスが、 sshconn リストに、 ここ 60 秒間で 5 回以上記録されていたら「これは brute force attack だ」と判断します。 SSH-evil チェインに飛びます。
2. と 3. のルールにマッチしなかった場合、 sshconn リストにパ ケットの source IP アドレスを記録します。この記録で 3. の判定が決 まります。
4. の記録が済んだら ACCEPT します。
SSH チェインの 3. から入ってきます。ここに来たパケットは、次の条 件を満たすものです。
brute force attack が行われていると判断し、このパケットの source IP アドレスを BadSSH リストに登録して、ログをとります。
パケットを REJECT します。
[4] | 例えば $IPTABLES -A INPUT -p tcp --dport ssh -j SSH 。 |
この例は次のメーリングリストへの投稿を参考にしました。 http://lists.suse.com/archive/suse-security/2005-Feb/0026.html
この方法にも弱点があります。ログイン試行を受け入れるかどうかの判断が、 ホストベース(IP アドレスベース)でしかできないことです。
ここで、 Bob さんは Alice さんがホスト R へログインするのを妨害できま す。 Bob さんがホスト R へのログイン試行をひたすら繰り返していると、ホ スト R の SSH-evil チェインには常にホスト L のアドレスが記録され続ける ことになり、 Alice さんはホスト R にログインできなくなってしまいます。
この問題に対処しようとすると ssh の通信内容を知る必要が出てくるため、 iptables だけでは対処のしようがありません。もっとも、この問題に対策を しようとすると(1ユーザごとに n 回まで試行可能、などの設定ができるよう にすると)、対策にスキができてしまいます。つまり「ユーザ名を変えて同じ パスワードを試し続ける」というタイプの攻撃( brute force attack とは の例を参照)に全く無防備になってしまいます。 あきらめた方がいい、というのが私の結論です。
なお、 source IP アドレスを偽装したパケットを送りつけることでも同様の 攻撃が行えますが、この場合は上記 Netfilter Extensions HOWTO の通り --rttl オプションを使用すればある程度の対策が行えるようです(当方では 動作未確認)。
以下では、このドキュメントで触れなかった brute force attack 対策の方法 について挙げておきます。
通常、攻撃者は 22/tcp を listen しているプロセスがいるかどうかで ssh を使っているかどうか確認する(と思う)ので、 sshd が listen するポート を、例えば 8022/tcp とかに変えてしまえば攻撃の頻度は一気に下がります (と思います)。
sshd が listen するポートの設定は、''/etc/ssh/sshd_config'' ファイルで 行えます。
以下、このドキュメントの対象に入らなかった話題やツールの紹介です。
[5] | 排除時間を長くしても、自分が締め出される心配がなくなります。否 定的な意見も多いポートノッキングですが、こういう使いかたなら大 丈夫じゃないかと思います。 |
このドキュメントに対するコメントです。
このドキュメントについてコメントする / コメントを全部見る