ここはyamagが {powder|white|tdiary}.nadare.netと自宅のLinuxBoxをいぢくった時のメモを書いておく場所なので、見てもつまんないと思いまっせ ;-)
ツッコミランキング1.satoshis(4) 2.TrackBack(2) 3.globe term life insurance(1) 4.xzhcrumw oksmcr(1) 5.online payday loan service(1)
Wed Feb 02, 2005 [長年日記]
#1 [Linux] Brute Force 攻撃防御
インターネットにサーバを晒していると、当然のことながら攻撃を受けるわけで、sshd 向けに絨毯爆撃しかけてくる連中を排除すべく、ちょっとしたスクリプトを書いて仕掛けました。
#!/usr/bin/perl $LogDir="/var/log"; $MsgFile="secure"; $DenyCnf="/etc/hosts.deny"; $Pattern="^([A-Z][a-z][a-z]) ([ 0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) .+ sshd\[[0-9]+\]: Failed password for illegal user ([^\S]+) from ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)"; $fsdev=0; $ino =1; $mode =2; $nlink=3; $owner=4; $group=5; $dev =6; $size =7; $atime=8; $mtime=9; $ctime=10; $bsize=11; $blks =12; $need_seek=0; # for DEBUG #$need_seek=1; $DEBUG=1; open(CNF, "< $DenyCnf") || die "file open error. $!\m"; while () { if ($_ =~ "^ALL:(.*)") { $denylist{$1}='1'; } } close(CNF); print "--denylist--\n"; foreach $deny ( keys(%denylist) ) { print "$deny\n"; } print "--denylist--\n"; while (true) { open(IN, "< $LogDir/$MsgFile") || die "file open error. $!\n"; if ($need_seek == 1) { seek(IN, 0, 2); $need_seek=0; } $rec_ptr=tell(IN); # print "DEBUG start pointer $rec_ptr\n"; while (true) { @w_fstat=stat("$LogDir/$MsgFile"); @c_fstat=stat(IN); # print "DEBUG size $w_fstat[$size] ptr $rec_ptr\n"; while ($c_fstat[$size] > $rec_ptr) { # print "DEBUG size $w_fstat[$size] ptr $rec_ptr\n"; $line= ; if ($line =~ $Pattern) { if (! exists $denylist{$5}) { print "catch $1_$2_$3_$4_$5\n"; $newdeny{$5}++; if ($newdeny{$5} > 5 || $4 eq "test" || $4 eq "guest" || $4 eq "admin" || $4 eq "user" ) { print "insert $1_$2_$3_$4_$5\n"; $denylist{$5}='1'; open(OUT,">> /etc/hosts.deny") || die "file open error. $!\n"; print OUT "ALL:$5\n"; close(OUT); } } } $rec_ptr=tell(IN); } last if ($c_fstat[$ino ] != $w_fstat[$ino ]); # print "DEBUG current ino %$c_fstat[$ino]%, file ino %$w_fstat[$ino]%\n" if ($DEBUG == 1); last if ($c_fstat[$size ] < $w_fstat[$size ]); sleep(1); } close(IN); $DEBUG=0; # print "DEBUG change log file"; }
このスクリプトは、sshでのログイン認証の失敗数をカウントしており、一定回数以上間違っていた場合や、testとかadminとか、明らかにアタックと判断されるアクセスがあった場合、自動的に deny.host リストにアドレスを追加して、攻撃をブロックするというものです。
ここ数日、このスクリプトを実行していますが、何件か引っかかったアホがおります。
catch Jan_29_12:17:28_patrick_61.100.6.70 catch Jan_29_12:17:31_patrick_61.100.6.70 catch Jan_29_12:17:50_rolo_61.100.6.70 catch Jan_29_12:17:53_iceuser_61.100.6.70 catch Jan_29_12:17:56_horde_61.100.6.70 catch Jan_29_12:17:59_cyrus_61.100.6.70 insert Jan_29_12:17:59_cyrus_61.100.6.70 catch Feb_ 1_02:10:19_test_65.33.111.160 insert Feb_ 1_02:10:19_test_65.33.111.160 catch Feb_ 1_09:50:10_test_67.108.93.195 insert Feb_ 1_09:50:10_test_67.108.93.195 catch Feb_ 2_07:09:54_test_218.65.87.12 insert Feb_ 2_07:09:54_test_218.65.87.12 catch Feb_ 2_09:50:28_patrick_195.70.36.86 catch Feb_ 2_09:50:33_patrick_195.70.36.86 catch Feb_ 2_09:51:03_rolo_195.70.36.86 catch Feb_ 2_09:51:08_iceuser_195.70.36.86 catch Feb_ 2_09:51:13_horde_195.70.36.86 catch Feb_ 2_09:51:18_cyrus_195.70.36.86 insert Feb_ 2_09:51:18_cyrus_195.70.36.86 catch Feb_ 2_16:15:13_test_67.70.221.189 insert Feb_ 2_16:15:13_test_67.70.221.189
本日のTrackBacks(全2件)
[]
攻撃に対して、自動的に対応するって良いですね。メールサーバへのSPAMアタックにもこういうの作れないかな…。
とりあえず、都度ログ全部なめてbadmailfromに突っ込むとこまではできました。ダサい…。
メール版作りました。使用するログがとあるウイルスチェックソフトのなんで公開できないのが残念ですが。<br>○ seek (IN,0,1); で、end-of-fileエラーをリセットできるとかなり幸せ。(cf.プログラミングPerl 関数seek解説)<br>○use FileHandle;.... ; OUT->autoflush(1);で、バッファ無しで即時追加。<br>○真似して、<br>last if ($inode != (stat($infile))[1]);<br>とやって、ログローテートしたときに、openし直すようにしてみたけどうまく行かなかったんで、cronで一分後に再起動。ダサいのが残ってしまいました。