セキュリティの危機を調べるshell script

上のようなイベント(インシデント)が、過去の一定時間の間に発生していたらメールで知らせるシェル・スクリプト、chkloginを載せておく。Fedora 8で動作確認をしているが、他のLinuxでも使えるかと思う。取り急ぎ作成したので、引数の処理などの汎用性は考慮してない。

     1	#! /bin/sh
     2	
     3	# chklogin Ver 0.0000000001 (2008/04/01)
     4	# Copyright (C) 2008 Adsaria
     5	
     6	# This program is free software; you can redistribute it and/or
     7	# modify it. This program is distributed in the hope
     8	# that it will be useful, but WITHOUT ANY WARRANTY.
     9	
    10	DEBUG=0					: Debug flag, 0 is no debug.
    11	
    12	CMD=`basename $0`
    13	
    14	#################### Environment dependent variables
    15	MAIL_TO=xxxxx@xxxxx.jp
    16	MAIL_SUBJECT="Security Warning from `hostname` by $CMD"
    17	ZIP_PASSWORD="xxxxx"
    18	####################
    19	
    20	NOW=`date +%s`				: Current time in seconds since 1970-01-01
    21	SPAN=3660				: Time span in seconds
    22	PAST=`expr \`date +%s \` - $SPAN`	: Spaned past tiem in seconds since 1970-01-01
    23	SEND_MAIL="no"				: Flag for sending mail or not
    24	MARK="$CMD.$NOW.MARK"			: Marking string definition
    25	
    26	# Temporary files
    27	MESSAGE_FILE=/tmp/${CMD}_${NOW}_$$_massagel.txt ; rm -f $MESSAGE_FILE
    28	MESSAGE_ZIP_FILE=${MESSAGE_FILE}.zip
    29	TMP_FILE_1=/tmp/${CMD}_${NOW}_$$_secure_tmp_1 ; rm -f $TMP_FILE_1
    30	TMP_FILE_2=/tmp/${CMD}_${NOW}_$$_secure_tmp_2 ; rm -f $TMP_FILE_2
    31	
    32	echo "`date` = `date -u`" >> $MESSAGE_FILE; echo >> $MESSAGE_FILE
    33	
    34	##### Check SSH connection close
    35	
    36	grep -E "sshd\[[0-9]+\]: Connection closed" /var/log/secure > $TMP_FILE_1
    37	date -u -d @"$PAST" +"%b %e %T $MARK" >> $TMP_FILE_1
    38	sort -k 1M -k 2n -k 3 $TMP_FILE_1 > $TMP_FILE_2
    39	
    40	if [ $DEBUG -gt 0 ]; then tail $TMP_FILE_2; echo; fi
    41	
    42	sed -i -e "1,/.* $MARK/d" \
    43		-e "/^[ 	]*$/d" \
    44		$TMP_FILE_2
    45	
    46	if [ $DEBUG -gt 0 ]; then cat $TMP_FILE_2; echo; fi
    47	
    48	if [ -s $TMP_FILE_2 ]; then
    49		SEND_MAIL="yes"
    50		echo "There is at least one SSH connection close in $SPAN seconds" >> $MESSAGE_FILE
    51		cat $TMP_FILE_2 >> $MESSAGE_FILE ; echo >> $MESSAGE_FILE
    52	fi
    53	
    54	##### Check failed login
    55	
    56	grep "Failed password for" /var/log/secure > $TMP_FILE_1
    57	date -u -d @"$PAST" +"%b %e %T $MARK" >> $TMP_FILE_1
    58	sort -k 1M -k 2n -k 3 $TMP_FILE_1 > $TMP_FILE_2
    59	
    60	if [ $DEBUG -gt 0 ]; then tail $TMP_FILE_2; echo; fi
    61	
    62	sed -i -e "1,/.* $MARK/d" \
    63		-e "/^[ 	]*$/d" \
    64		$TMP_FILE_2
    65	
    66	if [ $DEBUG -gt 0 ]; then cat $TMP_FILE_2; echo; fi
    67	
    68	if [ -s $TMP_FILE_2 ]; then
    69		SEND_MAIL="yes"
    70		echo "There is at least one password failure in $SPAN seconds" >> $MESSAGE_FILE
    71		cat $TMP_FILE_2 >> $MESSAGE_FILE ; echo >> $MESSAGE_FILE
    72	fi
    73	
    74	##### Check login
    75	
    76	last -a | head -n -2 > $TMP_FILE_1
    77	date -d @"$PAST" +"-------- ------------ %a %b %e %H:%M - ------------------ $MARK" >> $TMP_FILE_1
    78	
    79	sort -t \* -f -k 1.27M -k 1.31n -k 1.34 $TMP_FILE_1 > $TMP_FILE_2
    80	
    81	if [ $DEBUG -gt 0 ]; then tail $TMP_FILE_2; echo; fi
    82	
    83	sed -i -e "1,/.* $MARK/d" \
    84		-e "/^[ 	]*$/d" \
    85		$TMP_FILE_2
    86	
    87	if [ $DEBUG -gt 0 ]; then cat $TMP_FILE_2; echo; fi
    88	
    89	if [ -s $TMP_FILE_2 ]; then
    90		SEND_MAIL="yes"
    91		echo "There is at least one login in $SPAN seconds" >> $MESSAGE_FILE
    92		cat $TMP_FILE_2 >> $MESSAGE_FILE ; echo >> $MESSAGE_FILE
    93	fi
    94	
    95	if [ $SEND_MAIL = "yes" ]; then
    96		if [ $DEBUG -gt 0 ]; then
    97			echo "+++++"
    98			cat $MESSAGE_FILE
    99			echo "+++++"
   100		else
   101			logger "Security Warning by $CMD"
   102			zip -q -P "$ZIP_PASSWORD" - $MESSAGE_FILE > $MESSAGE_ZIP_FILE
   103			echo "Security Warning by $CMD" | \
   104				mutt -s "$MAIL_SUBJECT" -a $MESSAGE_ZIP_FILE -- $MAIL_TO
   105		fi
   106	fi
   107	
   108	rm -f $TMP_FILE_1
   109	rm -f $TMP_FILE_2
   110	rm -f $MESSAGE_FILE
   111	rm -f $MESSAGE_ZIP_FILE

簡単なプログラムなので、特段説明は必要ないと思うが、"/var/log/secure "に記録されるログはUTC(Universal Time Coordinated)で記録されるが、lastコマンドの出力はローカルタイムなので、dateコマンドの扱いが微妙に異なっている。

この例では1時間1分(3660秒)以内にSSHコネクションのグローズやログインがあった場合には、そのログをZIPで暗号化してメールに添付して送信する。メールに添付した暗号付きZIPファイルを解凍すると次のようなメッセージが報告される。

Wed Apr  2 00:33:58 JST 2008 = Tue Apr  1 15:33:58 UTC 2008

There is at least one SSH connection close in 3660 seconds
Apr  1 15:01:03 accessserv sshd[18438]: Connection closed by 192.168.0.128

There is at least one login in 3660 seconds
guest    pts/3        Wed Apr  2 00:02 - 00:02  (00:00)     192.168.0.128

(最初の行にローカルタイムと協定世界時の両方を記録している。)

このchkloginというシェル・スクリプトをcronで1時間おきに動かすようにしている。

[root@accessserv ~]# crontab -e
0 * * * * /usr/local/bin/chklogin

なお、チェックの頻度を短くする場合はcronの設定を変えると同時に、chkloginの21行目の"SPAN"という変数の値も変更する。例えば15分であれば960にする(15分=900秒よりも若干長い時間にしておく。cronの間隔と丁度同じ間隔で設定した場合、マシンの負荷が多くコマンドの起動に時間がかかると、空白の時間が出来きてしまう。)