OXY NOTES

Swatchでログを監視して、攻撃に合わせた対策を自動で実行する方法

ハッカーからの攻撃に対して、千手観音のような活躍をみせるSwatchの応用編

前回の投稿でSwatchの基本的な使い方を解説しました。

このページではiptablesでアクセスを遮断したり、攻撃に使われたIPに関する情報をメールに追加したりと、外部スクリプトと連携する方法を解説します。
合わせてSwatchの設定を一元管理する方法。一連の処理をテスト・調整する方法も解説します。

また、投稿の最後には実際に運用している設定の例を掲載しています。

このページで紹介するスクリプトは以下のサイトで紹介されている方法を元に手を加えたものです。この場を借りてお礼申し上げます。

http://centossrv.com/swatch.shtml

目次

Swatchによって実行されるスクリプトを作成
swatch.logのログローテーションを設定
BIND用の設定ファイルを作成
Swatchの起動スクリプトを作成
動作テスト用にスクリプトを変更
テスト方法1「実際にBINDのバージョンを問い合わせる」
テスト方法2「対象のログを自分で追加する」
実際に運用している設定の例
 BINDのlogに対する設定ファイル
 メールのlogに対する設定ファイル
 SSLのlogに対する設定ファイル
 iptablesのlogに対する設定ファイル
 nginxのログに対する設定ファイル(WordPress用)


Swatchによって実行されるスクリプトを作成

まずはSwatchでパターンに一致した際に実行するスクリプトを作成します。

# vi /usr/local/bin/swatch_action.sh
#!/bin/bash

PATH=/bin:/sbin:/usr/bin

# 出力を英語に統一(-dを使う都合上)
LANG=C

# 規制IPアドレス情報メール通知先設定
# ※メール通知しない場合は下記をコメントアウト
mail=root

# ログを標準入力から取得
read LOG

# ログからIPアドレスを抽出(オリジナルだと抽出できない場合があるため変更)
IPADDR=`echo $LOG|cut -d " " -f $1`
IPADDR=`echo "$IPADDR"|grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}'`

# IPアドレスをピリオドで分割
addr1=`echo $IPADDR|cut -d . -f 1`
addr2=`echo $IPADDR|cut -d . -f 2`
addr3=`echo $IPADDR|cut -d . -f 3`
addr4=`echo $IPADDR|cut -d . -f 4`

# IPアドレスがプライベートIPアドレスの場合は終了
if [ "$IPADDR" = "127.0.0.1" ]; then
	exit
elif [ $addr1 -eq 10 ]; then
	exit
elif [ $addr1 -eq 172 ] && [ $addr2 -ge 16 ] && [ $addr2 -le 31 ]; then
	exit
elif [ $addr1 -eq 192 ] && [ $addr2 -eq 168 ]; then
	exit
fi

# IPアドレスがホワイトリストに一致する場合は終了
# この例では100.100.0.0/16を想定(環境によって適宜変更してください)
if [ $addr1 -eq 100 ] && [ $addr2 -eq 100 ] && [ $addr3 -lt 256 ] && [ $addr4 -lt 256 ]; then
	exit
fi

# 不正アクセスログメッセージをIPアドレス別ログファイルに記録
echo $LOG >> /var/log/swatch/$IPADDR

# IPリストにIPが含まれている場合は終了
# file=`cat /root/test_ip`
file=`cat /root/deny_ip`
echo "$file" | grep "$IPADDR"
if [ $? -eq 0 ];
then
        exit
fi

# IPアドレス別ログファイルから累積不正アクセス数取得
cnt=`cat /var/log/swatch/$IPADDR | wc -l`

# 該当IPアドレスからの累積不正アクセス数が3以上の場合
# IPリストへ書き出し、1週間後ブロック解除、メールでの通知
if [ $cnt -ge 3 ] ; then

	# 該当IPアドレスをdeny_ipに登録
	# echo "$IPADDR" >> /root/test_ip
	echo "$IPADDR" >> /root/deny_ip

	# 上記リストに追加したIPを1週間で削除するスケジュールを予め登録
	# echo "sed -i "/$IPADDR/d" /root/test_ip" | \
	echo "sed -i "/$IPADDR/d" /root/deny_ip" | \
	at now+1weeks > /dev/null 2>&1

	# アクセス規制IPアドレス情報をメール通知
	[ "$mail" != "" ] && (cat /var/log/swatch/$IPADDR ; \
		echo ; whois $IPADDR) | \
		mail -s "$IPADDR $cnt lock!" $mail

	echo "`date` $IPADDR $cnt lock!"

# 引数でlockと指定された不正アクセスの場合
# IPリストへ書き出し、即ブロック、1ヵ月後ブロック解除、メールでの通知
elif [ $# -eq 2 -a  "$2" = "lock" ]; then

	# 該当IPアドレスを拒否する設定をiptablesに追加
	# (オリジナルだと削除する設定もあるがcronで毎日deny_ipを拒否するため不要)
	iptables -I INPUT -s $IPADDR -j DROP

	# 該当IPアドレスをdeny_ipに登録
	# echo "$IPADDR" >> /root/test_ip
	echo "$IPADDR" >> /root/deny_ip

	# 上記リストに追加したIPを4週間で削除するスケジュールを予め登録
	# echo "sed -i "/$IPADDR/d" /root/test_ip" | \
	echo "sed -i "/$IPADDR/d" /root/deny_ip" | \
	at now+4weeks > /dev/null 2>&1

	# アクセス規制IPアドレス情報をメール通知
	[ "$mail" != "" ] && (cat /var/log/swatch/$IPADDR ; \
		echo ; whois $IPADDR) | \
		mail -s "$IPADDR $cnt lock!" $mail

	echo "`date` $IPADDR $cnt lock!"

else
	echo "`date` $IPADDR $cnt"
fi

それぞれの役割をコメントで解説しているので、bashの基礎を学んだ方なら理解できると思います。

$1」や「$2」といった引数がありますが、これは後ほど作成する設定ファイルで定義します。後ほど詳しく解説するので、わからない場合読み飛ばしてください。

16~17行目、オリジナルの方法だと数字以外で始まる場合や、区切り文字が変則的だと上手く取得できないことがあったのでsedコマンドを使った方法から、grepコマンドを使う方法に変更しています。

38~40行目、設定を誤って自分のIPが拒否されてしまわないようにホワイトリストを設定しています。リストに一致した場合にはスクリプトを終了させます。ISPに割り当てられているIP等を登録しておくと安心です。

47~52行目、ログでマッチしたIPを「/root/deny_ip」に書き出し、そのリストにIPが存在する場合はスクリプトを終了させます。
こうすることでDos攻撃など同じIPで短時間に連続した攻撃があった場合でも、アクションの重複を防ぐことができます。

ここでIPを書き出す「/root/deny_ip」は過去の投稿「iptablesの設定ファイルをシェルスクリプトを利用して動的に作成」の中で、このリストにあるIPを拒否するというスクリプトを作成しました。
同じように動作させたい場合は参照してください。

59~103行目、ここが実際に実行されるアクションです。オリジナルのものは同じIPが3回カウントされた場合か、引数にlockとある場合に同じ処理を指定ましたが、当サイトの解説ではそれぞれ別の処理を指定ます。
拒否IPリストの「/root/deny_ip」にIPを書き出して、一定の時間が経過したらリストから削除。そのIPに関する情報を調べてメールで送信する。
/root/deny_ip」によるIPの拒否はCronによって毎日一度だけ実行されます。
対して引数にlockとあるものはiptablesで拒否リストに即登録されます。

このように引数によって複数のアクションを登録しておけば、攻撃の種類によって対応を分けることができます。

以上、スクリプトを作成したら、続いてIPを保存する「deny_ip」と、テストの時に利用する「test_ip」を作成。続けてSWATCHアクションスクリプトへ実行権限付加。

# echo -n > /root/deny_ip
# echo -n > /root/test_ip
# chmod 700 /usr/local/bin/swatch_action.sh

swatch.logのログローテーションを設定

コチラはオリジナルのものをそのまま利用させていただきます。
解説のコメントを追加したので理解できると思います。「rsyslogのログローテーションについて」知りたい方は過去の投稿を参照してください。

# mkdir /etc/swatch ← SWATCH設定ファイル格納ディレクトリ作成
# vi /etc/logrotate.d/swatch ← SWATCHログ切替え設定ファイル作成
/var/log/swatch/swatch.log {
	missingok # ログファイルがなくてもエラーを出さない
	notifempty # logファイルが空の時はrotateしない
	sharedscripts # postrotateまたはprerotateで記述したコマンドを実行
	postrotate # ここからendscriptまでを実行
		/etc/rc.d/init.d/swatch restart > /dev/null || true # ログの書き換えに際してswatchを再起動
	endscript
}

BIND用の設定ファイルを作成

このページではBINDのログを想定して設定ファイルを作成します。
BINDのロギングについては「BINDのlogを適切に設定して攻撃の予兆を察知しよう」でまとめたので参照してください。

BINDのバージョンの問い合わせはハッカーが脆弱性のあるバージョンであるか調査する際に使います。

# logfile /var/log/named/default.log

# BINDのバージョン照会を検知したら該当ホストからのアクセスを24時間規制
watchfor /query \'VERSION\.BIND\/TXT\/CH\' denied/i
	pipe "/usr/local/bin/swatch_action.sh 6 lock"
	throttle=00:00:10

1行目、対象となるログファイルを指定します。この書式は後に作成するスクリプトで利用するため同じ書式で記述してください。

6行目、上の行にあるログに一致するパターンを記述。

7行目、「pipe “~”」で先ほど作成したスクリプトを指定。それに続いてスペース区切りで「6」と「lock」が追加されています。
このようにスペース区切りで記述することで実行するスクリプトに引数を渡すことができます。「6」を取り出す場合は「$1」。「lock」を取り出す場合は「$2」となります。
ちなみに第1引数の「6」はログの行頭からスペース区切りでいくつ目のフィールドにIPアドレスがあるかを指定するためのものです。ログによっては複数のIPが記述されている場合があるので、アクセスを規制するIPを指定する必要があります。

8行目throttleはで実行する間隔を指定しています。10秒以内に何度もログが出力されても、10秒に1回しか実行しないという意味です。

ログの形式を検査する

BINDのバージョンを問い合わせたり、ポートスキャンを行ったりという攻撃の予兆はありきたりのものです。そこで手っ取り早くネット上のログや、別サーバが攻撃された際のログを参考にして設定を書きたいところですが、注意が必要です。
ディストリビューションやソフトのバージョンによってログの形式に揺れがあるためです。

自分のサーバからdigコマンドを利用しても同じように表示されないので、windows上からdigコマンドを利用してBINDのバージョンを調べます。
windowsでdigコマンドを利用する方法」は以前の投稿を参照してください。

Windows上のコマンドプロンプトで以下のコマンドを打てばBINDのバージョンを調べることができます。「ns.example.com」の部分は自分で構築したDNSサーバに合わせてください。

# dig @ns.example.com chaos txt version.bind

続いてlinux側に戻り、どのようにlogに書きだされるのかを調べてみます。

# cat /var/log/named/default.log

オリジナルの例では以下の様なログを想定してパターンを定義していました。

Oct 21 05:20:12 centos named[14130]: client XXX.XXX.XXX.XXX#55199: query 'VERSION.BIND/TXT/CH' denied

しかし実際にdigコマンドを利用してアクセスしてみると以下のように出力されていました。

12-Aug-2014 08:07:43.478 security: info: client XXX.XXX.XXX.XXX#58874: query 'version.bind/TXT/CH' denied

swatch_action.sh」の後にあるIPのあるフィールドを示す数字ですが、今回のテストでは「7つ目の項目」ではなく、「6つ目の項目」にIPが記述されています。

また一致するパターンで「VERSION\.BIND」と大文字で指定されていましたが、テストの結果は「version.bind」なので、このままではパターンに一致しません。
そこでパターンの項目に「i」を付けて大文字小文字どちらでも一致するように変更しました。

以上のように環境によって表現に揺れがあるので、できれば実際のログを参照して設定を行うようにしてください。


Swatchの起動スクリプトを作成

Swatchプロセスを起動するには以下のように設定ファイルと対象となるログファイルを指定する必要がありました。

swatch -c 設定ファイル -t 対象ログファイル &

また、終了時にはプロセスナンバーを調べて1つずつ停止しなくてはなりません。

監視するログが増えたり、サーバを再起動するごとにコマンドを打つのは現実的ではありません。そこでSwatchの起動スクリプトを作成して、一括で起動・終了を行えるようにします。

# vi /etc/rc.d/init.d/swatch
#!/bin/bash
#
# swatch
#
# chkconfig: 2345 90 35
# description: swatch start/stop script

# Source function library.
. /etc/rc.d/init.d/functions

PATH=/sbin:/usr/local/bin:/bin:/usr/bin

mkdir -p /var/log/swatch

start() {
	# Start daemons.
	ls /var/run/swatch_*.pid > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo -n "Starting swatch"
		pno=0
		for conf in /etc/swatch/*.conf
		do
			pno=`expr $pno + 1`
			WATCHLOG=`grep "^# logfile" $conf | awk '{ print $3 }'`
			swatch --config-file $conf --tail-file $WATCHLOG \
			--script-dir=/tmp --awk-field-syntax --use-cpan-file-tail --daemon \
			--pid-file /var/run/swatch_$pno.pid \
			>> /var/log/swatch/swatch.log 2>&1
			RETVAL=$?
			[ $RETVAL != 0 ] && return $RETVAL
		done
		echo
		[ $RETVAL = 0 ] && touch /var/lock/subsys/swatch
		return $RETVAL
	else
		echo "swatch is already started"
	fi
}

stop() {
	# Stop daemons.
	ls /var/run/swatch_*.pid > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo -n "Shutting down swatch"
		for pid in /var/run/swatch_*.pid
		do
			kill $(cat $pid)
			rm -f $pid
		done
		echo
		rm -f /var/lock/subsys/swatch /tmp/.swatch_script.*
	else
		echo "swatch is not running"
	fi
}

status() {
	ls /var/run/swatch_*.pid > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo -n "swatch (pid"
		for pid in /var/run/swatch_*.pid
		do
			echo -n " `cat $pid`"
		done
		echo ") is running..."
	else
		echo "swatch is stopped"
	fi
}

case "$1" in
	start)
	        start
	        ;;
	stop)
	        stop
	        ;;
	restart)
		stop
		start
		;;
	status)
		status
		;;
	*)
		echo "Usage: swatch {start|stop|restart|status}"
		exit 1
esac

exit $RETVAL

起動スクリプトの詳細を追うと長くなってしまうので、一般的な設定は飛ばして、ポイントだけ紹介します。

1.Swatch用のログファイルを保存する「/var/log/swatch」というディレクトリを作成しています。

そして起動時に「/etc/swatch/」にある拡張子が「.conf」のファイルを全て実行。
監視するログファイルは「WATCHLOG=」の行で定義しています。このなかで「# logfile」の行を参照しているので、各設定ファイルで「# logfile xxx」の記述を省略せず記載しないと正しく動作しないので注意してください。

停止時に「/var/run/」にある「swatch_*.pid」というプロセスを全て終了させています。

続けてSWATCH起動スクリプトへ実行権限を付加します。

# chmod +x /etc/rc.d/init.d/swatch

SWATCH起動します。

# /etc/rc.d/init.d/swatch start
Starting swatch

もし以下のように表示される場合は「/etc/swatch/」ディレクトリに「.conf」という拡張子のファイルが作成されていません。

Starting swatchgrep: /etc/swatch/*.conf: No such file or directory

正しく起動できたら「/var/run」に「swatch_*.pid」というプロセスが起動しているか調べます。(*の部分は数字)

# cd /var/run
# ls -l

プロセスが起動しない場合はswatchのログファイル「/var/log/swatch/swatch.log」を見てください。私の場合は以下のエラーが出ていました。

Can't locate File/Tail.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /tmp/.swatch_script.16445 line 90.

これはPerlのライブラリ「File/Tail.pm」が存在しないとエラーが出ています。
yumを利用して調べてみます。

CentOS6.5では公式から見つけられなかったのでepelリポジトリを追加して調べます。

# yum --enablerepo=epel provides '*File/Tail.pm'

perl-File-Tail-0.99.3-8.el6.noarch : Perl extension for reading from continously
                                   : updated files

目的のファイルが「perl-File-Tail」にあるようなのでインストールします。

# yum --enablerepo=epel install perl-File-Tail
(省略)
Dependencies Resolved

================================================================================
 Package                Arch           Version               Repository    Size
================================================================================
Installing:
 perl-File-Tail         noarch         0.99.3-8.el6          epel          23 k

Transaction Summary
================================================================================
Install       1 Package(s)
(省略)

これで無事インストール完了。再び起動します。

# /etc/rc.d/init.d/swatch start

そして再びプロセスが作成されているか調べます。

# cd /var/run
# ls -l

-rw-r--r-- 1 root  root       6 Aug 13 10:52 swatch_1.pid

どうやら無事に起動できているようなので、SWATCH起動スクリプトをcheconfigへ登録します。

# chkconfig --add swatch

SWATCH自動起動を有効にして、確認をします。

# chkconfig swatch on
# chkconfig --list swatch
swatch          0:off   1:off   2:on    3:on    4:on    5:on    6:off ← ランレベル2~5のonを確認

以上で起動スクリプトの設定は全て終了です。
これで次回からは「/etc/swatch/」に作成した設定ファイルを一括で起動したり、停止することができるようになりました。

# /etc/rc.d/init.d/swatch start ← 起動
# /etc/rc.d/init.d/swatch stop ← 停止
# /etc/rc.d/init.d/swatch restart ← 再起動

動作テスト用にスクリプトを変更

BINDの例でテストが重要な事が理解していただけたと思います。
これから全体のテストを行いますが、テストの際に実際にファイアーウォールで遮断されると困るので、スクリプトをテスト用に変更します。

基本的にはIPの出力先を実際に利用する「deny_ip」から「test_ip」に変更して、「iptables -I INPUT -s $IPADDR -j DROP」をコメントアウトしているだけです。
長くなるので変更箇所だけ記載します。

# vi /usr/local/bin/swatch_action.sh

46~47行目
file=`cat /root/test_ip`
# file=`cat /root/deny_ip`

62~63行目
echo "$IPADDR" >> /root/test_ip
# echo "$IPADDR" >> /root/deny_ip

66~67行目
echo "sed -i "/$IPADDR/d" /root/test_ip" | \
# echo "sed -i "/$IPADDR/d" /root/deny_ip" | \

83行目
# iptables -I INPUT -s $IPADDR -j DROP

86~87行目
echo "$IPADDR" >> /root/test_ip
# echo "$IPADDR" >> /root/deny_ip

90~91行目
echo "sed -i "/$IPADDR/d" /root/test_ip" | \
# echo "sed -i "/$IPADDR/d" /root/deny_ip" | \

テスト方法1、実際にBINDのバージョンを問い合わせる

外部サーバからdigコマンドを利用すると簡単にテストができます。Windows上でコマンドプロンプトから実行します。digコマンドのWindowsへのインストールは以前の投稿を参照してください。

またBINDのログは「/var/log/named/default.log」に書きだされていると仮定しています。

Windowsのコマンドプロンプトで以下のように入力します。(example.comの部分はサイトに合わせて変更してください)

# dig @ns.example.com chaos txt version.bind

正しく動作していれば初回テスト時に以下のアクションが実行されます。

全て正しく実行されたことを確認したら、もう一度BINDの問い合わせを実行してください。
既に「/root/test_ip」にIPが追加されているため、登録の有無を確認するスクリプト以降は実行されません。そのため「/root/test_ip」にIPがダブって登録されたり、同じIPに関するメールは届きません。

このように設定することでDOS攻撃など連続した攻撃が発生した祭に、無駄にサーバリソースを消費することが無くなります。

もし「/var/log/swatch/swatch.log」に以下の様なログが表示されるようなら、ログに出力されたIPのフィールドを正しく指定できていません。

/usr/local/bin/swatch_action.sh: line 35: [: -eq: unary operator expected

以上で一連のログの監視とIPリストへの書き出し、メールでの通知が動作することが確認できました。


テスト方法2、対象のログを自分で追加する

上記のように自分で簡単にテストできるログの場合はいいのですが、ブルートフォース攻撃やDos攻撃のログを再現するために自分のサーバ対してテストを行うのは問題があります。
実際にサーバへ影響が出ればハッキング行為となんら変わりが無いからです。

そのような場合は想定される攻撃が起きた際のログを自分で作成してテストします。
上記の例で解説します。「動作テスト用にスクリプトを変更」を修正後作業してください。

監視用のログファイルを「/root/test.log」に変更するという修正です。

# echo -n > /root/test.log ← テスト用のlogファイルを作成
# vi /etc/swatch/named-default.conf ← 続いてログファイルの修正
# logfile /root/test.log
## logfile /var/log/named/default.log(こっちが本番用)

# BINDのバージョン照会を検知したら該当ホストからのアクセスを24時間規制
watchfor /query \'VERSION\.BIND\/TXT\/CH\' denied/i
	pipe "/usr/local/bin/swatch_action.sh 6 lock"
	throttle=00:00:10

以上設定が終わったらSwatchを再起動して実際にログを追加してみます。

# vi /root/test.log
12-Aug-2014 00:00:00.000 security: info: client 100.100.100.100#58874: query 'version.bind/TXT/CH' denied

追加が終わったら保存してください。

無事に「/root/test_ip」に「100.100.100.100」というIPが追加されていればテストは成功です。


実際に運用している設定の例

サーバが違えば、構成や規模・対象としているログも千差万別のため、logファイルを睨みながら1つ1つ設定するのが王道です。
そうは言っても「異常なlogが出力されてからでは遅い」という考え方もあるので設定の例を紹介します。

BINDのlogに対する設定ファイル

上記の例ではBINDにバージョン紹介をしたらアクセス規制しました。
今度はDNS AMP対策で、BIND側でオープンリゾルバ対策をしているにもかかわらず、外部から名前解決を問い合わせた場合アクセスを規制します。

# vi /etc/swatch/named-default.conf
# logfile /var/log/named/default.log

# BINDのバージョン照会を検知したら該当ホストからのアクセス規制
# 対象ログ
# 12-Aug-2014 00:00:00.000 security: info: client xxx.xxx.xxx.xxx#58874: query 'version.bind/TXT/CH' denied
watchfor /query \'VERSION\.BIND\/TXT\/CH\' denied/i
	pipe "/usr/local/bin/swatch_action.sh lock"
	throttle=00:00:10

# BINDへ外部外部から名前解決の問い合わせを受けた場合アクセス規制(DNS AMP対策)
# 対象ログ
# 14-Aug-2014 00:00:00.000 security: info: client xxx.xxx.xxx.xxx#35688: query (cache) 'isc.org/ANY/IN' denied
watchfor /query \(cache\).*\/ANY\/IN\' denied/i
	pipe "/usr/local/bin/swatch_action.sh lock"
	threshold=track_by="/query/",type=threshold,count=5,seconds=300

アクションで「threshold」を利用し、「type」で「threshold」を指定しているので、最初のカウントから300秒位内に、5回カウントされたら、「swatch_action.sh」が実行されます。

注意点として、「threshold」はIP別にカウントするわけでなく、パターンにマッチした場合にカウントします。そのため4回は1.1.1.1というIPでマッチして、最後の1回は2.2.2.2でマッチした場合、スクリプトに渡されるログは2.2.2.2のものになります。厳密に運用したい場合はswatch_action.shでIP別にカウントして振り分ける必要があります。

「track_by=」でエスケープが必要な場合は「""」で囲むと動作しません。

このようにSwatch側の制御と、外部スクリプト(swatch_action.sh)を組み合わせればしきい値を柔軟に設定することができます。

メールのlogに対する設定ファイル

メールはPostfixDovecotを想定しています。
postfix側の設定で「smtpd_client_connection_rate_limit」を設定する事もできますが、より上流で制御したほうが負荷が軽く済みます。

# postfix認証失敗を5分間に5回の失敗を3回したらアクセス規制
# 対象ログ
# Aug 12 00:00:00 example.com postfix/smtpd[30277]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: authentication failure
watchfor /postfix.*authentication failure/
	pipe "/usr/local/bin/swatch_action.sh 7"
	threshold=track_by="/authentication failure/",type=threshold,count=5,seconds=300

# dovecot認証失敗を5分間に5回の失敗を3回したらアクセス規制
# 対象ログ
# Aug 15 00:00:00 example.com dovecot: pop3-login: Disconnected (auth failed, 1 attempts): user=<hoge>, method=PLAIN, rip=xxx.xxx.xxx.xxx, lip=xxx.xxx.xxx.xxx, TLS: Disconnected
watchfor /dovecot.*TLS: Disconnected/
	pipe "/usr/local/bin/swatch_action.sh 14"
	threshold=track_by="/Disconnected/",type=threshold,count=5,seconds=300

SSLのlogに対する設定ファイル

不正ログインのブルートフォース攻撃などが記録される「/var/log/secure」。
根本的な対処はSSLのポート変更、認証を許可するIPの制限、認証を鍵認証に変更するといった対策です。以上の対策を行っていれば何度ログインを施行しても破られることはありませんが、攻撃の意図をもったIPを把握するには役立ちます。

# vi /etc/swatch/secure.conf
# logfile /var/log/secure

# 登録していないユーザー名でのログインはアクセス規制
# 対象ログ
# Aug 26 00:00:00 example.com sshd[23540]: Invalid user hoge from xxx.xxx.xxx.xxx
watchfor /Invalid user.*from/
	pipe "/usr/local/bin/swatch_action.sh 10 lock"
	threshold=track_by="/Invalid user/",type=threshold,count=5,seconds=300

# ログイン時にパスワードを間違えた場合はアクセス規制
# そもそも鍵認証なのでパスワードを入力する行為自体が不正アクセスの証拠
# 対象ログ
# Aug 26 00:00:00 example.com sshd[23522]: Failed password for hoge from xxx.xxx.xxx.xxx port 58532 ssh2
watchfor /Failed password.*from/i
	pipe "/usr/local/bin/swatch_action.sh 11 lock"
	threshold=track_by="/Failed password/i",type=threshold,count=5,seconds=300

iptablesのlogに対する設定ファイル

iptablesでログを出力し、rsyslogでログの管理をしていることが前提となります。

iptablesの設定方法については「iptablesの設定ファイルをシェルスクリプトを利用して動的に作成」。
rsyslogについては「rsyslogを利用したログファイル作成と、logrotateを利用したログのローテーション」を参照してください。

ping攻撃用

Pingは短時間に大量にアクセスされることがあるので、thresholdのlimitモジュールで1分に1度しか実行されないように制限しています。

# vi /etc/swatch/iptables-ping-ataack.conf
# logfile /var/log/iptables-ping-ataack.log

# ping攻撃をしたIPをアクセス規制
# 対象ログ
# Jun 16 00:00:00 example.com kernel: [IPTABLES PINGATTACK] : IN=eth0 OUT= MAC=00:16:3e:4a:04:86:f8:72:ea:d8:34:ff:08:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=60 TOS=0x00 PREC=0x00 TTL=1 ID=14824 PROTO=ICMP TYPE=8 CODE=0 ID=14702 SEQ=33478
watchfor /IPTABLES PINGATTACK.*/
	pipe "/usr/local/bin/swatch_action.sh 12 lock"
	threshold=track_by="/IPTABLES PINGATTACK/",type=limit,count=1,seconds=60

input-drop用

input-dropはサーバで利用していないポートへのアクセスなどが記録されている。
このログではポートスキャンを察知することができる。thresholdのlimitで処理する数を10秒に1度に制限します。

# vi /etc/swatch/iptables-input-drop.conf
# logfile /var/log/iptables-input-drop.log

# サービスを提供していないPortにアクセスするIPをアクセス規制
# 対象ログ
# Jun 16 00:00:00 example.com kernel: [IPTABLES DROP INPUT] : IN=eth0 OUT= MAC=00:16:3e:4a:04:86:f8:72:ea:d8:34:ff:08:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=69 TOS=0x00 PREC=0x00 TTL=80 ID=63007 PROTO=UDP SPT=27838 DPT=53 LEN=49 
watchfor /IPTABLES DROP INPUT.*/
	pipe "/usr/local/bin/swatch_action.sh 13"
	threshold=track_by="/IPTABLES DROP INPUT/",type=threshold,limit=1,seconds=10

DNS Amp攻撃とキャッシュポイズニング(カミンスキー攻撃)用

こちらもBINDで根本的な対策をしたうえで設定する。
DNS Amp攻撃に対してはオープンリゾルバ対策。キャッシュポイズニングはソースポートランダマイゼーションとDNSSECの導入。

またBINDのログを適切に出力していることが前提となる。

# vi /etc/swatch/iptables-dnsamp.conf
# logfile /var/log/iptables-dnsamp.log

# DNS Ampもしくはカミンスキー攻撃用に5分で30アクセス以上は遮断
# iptablesのrecentで60秒に10回以上のアクセスはブロックしているがそれでもアクセスが続くようならdeny_ipに入れて長期間遮断するための設定
# 対象ログ
# Aug 19 00:00:00 example.com kernel: [IPTABLES DNSAMP] : IN=eth0 OUT= MAC=00:16:3e:4a:04:86:f8:72:ea:d8:34:ff:08:00 SRC=xxx.xxx.xxx.xxx DST=xxx.xxx.xxx.xxx LEN=69 TOS=0x00 PREC=0x00 TTL=79 ID=62983 PROTO=UDP SPT=58015 DPT=53 LEN=49 
watchfor /IPTABLES DNSAMP.*/
	pipe "/usr/local/bin/swatch_action.sh 12 lock"
	threshold=track_by="/IPTABLES DNSAMP/",type=threshold,count=30,seconds=300

nginxのログに対する設定ファイル(WordPress用)

大人気のWordPressはブルートフォース攻撃の対象になりやすいので対策します。

ログイン時にアクセスするwp-login.phpだけでなく、xmlrpc.phpも不正アクセスの原因になるので合わせて対策します。
また、ブルートフォース攻撃で負荷が異常にかかることもあるため、thresholdのlimitで処理する数を10秒に1度に制限します。

この設定はnginxでアクセスログを出力していることが前提となります。

# vi /etc/swatch/nginx-oxynotes.com_access.conf
# logfile /var/log/nginx/oxynotes.com_access.log

# WordPressのブルートフォース攻撃対策。
# 対象ログ
# xxx.xxx.xxx.xxx - - [27/Aug/2014:00:00:00 +0900] "GET /wp-login.php HTTP/1.1" 200 1400 "-" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36" "-"
watchfor /wp\-login\.php/
	pipe "/usr/local/bin/swatch_action.sh 1 lock"
	threshold=track_by=/wp\-login\.php/,type=threshold,limit=1,seconds=10

# 対象ログ
# xxx.xxx.xxx.xxx - - [27/Aug/2014:00:00:00 +0900] "GET /xmlrpc.php HTTP/1.1" 200 71 "-" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36" "-"
watchfor /xmlrpc\.php/
	pipe "/usr/local/bin/swatch_action.sh 1 lock"
	threshold=track_by=/xmlrpc\.php/,type=threshold,limit=1,seconds=10

以上でSwatchの応用編は終了です。
日々新しい攻撃方法が開発されているので、たまにはログファイルを開いて正しく防御できているか確認してください。