弁財天

ゴフマン「専門家を信じるのではなく、自分自身で考えて判断せよ」

Torの出口ノードを使ったDDOS攻撃をiptablesでブロック update4

何か特定のURLに対してDDOS攻撃されてるみたいだ。

攻撃のUserAgent文字列にWgetとか特徴があるので httpd.confでUAを特定してブロックすることが可能だ。

SetEnvIf User-Agent "^Wget/1.17.1" deny_agent # これ
Deny from env=deny_agent # これ

これがふつうの対処方法。いちばんHTTPサーバに負荷をかけない。 まるで何も起きてないかのよーに"403 Forbidden"エラー応答で遮断していく。

いやいや、せっかく特定の.cgiに対して攻撃に来てるのだから、IPアドレスを拾ってiptablesでブロックするってのはどうよ?w

じゃあアクセスしてきたIPアドレスをファイルに書き出すよーに修正してしまう。

/var/www/cgi-bin/hoge.cgi

#!/bin/sh
echo "Pragma: no-cache";
echo "Cache-Control: no-cache,must-revalidate"
echo "Cache-Control: post-check=0, pre-check=0"
echo "Expires: Thu, 01 Dec 1994 16:00:00 GMT"
echo "Content-type: text/html"
echo ""
echo "<html><body><pre>"
if [ "$HTTP_USER_AGENT" = "Wget/1.17.1 (linux-gnu)" ]; then
  F=`date '+%Y%m%d%H'`
  F2="/tmp/ip_${F}.txt"
  echo "$REMOTE_ADDR" >>${F2}
fi
echo "</pre></body></html>"
exit 0

で、IPアドレスからプレフィクスを求めてブロックするとかね。そんなことすると。ほぼ鎖国状態になるリスクが…。でもおもろいからやってみる。
/somewhere/prefix.pl

#!/usr/bin/perl

use utf8;
use strict;
use Encode;
use Net::Abuse::Utils qw( :all );

my %C;
my %R;

sub ip_asn() {
        my ($ip) = @_;
        my @ai = get_asn_info($ip);

        my $prefix = $ai[1];
        my @ac;
        @ac = get_as_company($ai[0]) if ($ai[0] ne "");
        my $company = $ac[0];

        if ($prefix =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+/) {
          $C{$prefix} = "# DDOS $prefix $company";
          $R{$prefix} = "-A INPUT -s $prefix -j REJECT --reject-with icmp-port-unreachable";
        }
}

while(<>) {
        chomp;
        &ip_asn($_) if (/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);
}

foreach my $p (keys(%R)) {
        print $C{$p} . "\n";
        print $R{$p} . "\n\n";
}

-A INPUT -s $prefix -j REJECT --reject-with icmp-port-unreachable
でブロックすると相手からは

TorのOrFoxだとこんなかんじ。
privoxy経由だと「404 No such domain」な応答になる。

プレフィクス単位にブロックするのはDHCPのアドレスがプレフィクスの範囲で変わると思うから。

/somewhere/ddos.sh

#!/bin/sh

cd /somewhere/ddos

cat before >iptables.new
sort /tmp/systemd-private-*-httpd.service-*/tmp/ip_*.txt|uniq|perl prefix.pl >>iptables.new
cat after >>iptables.new

systemctl stop iptables.service
cp iptables.new /etc/sysconfig/iptables
systemctl start iptables.service
systemctl status iptables.service
iptablesのルールにどんどん追加しちゃうw

crontab -l

*/15 * * * * /somewhere/ddos/ddos.sh > /somewhere/ddos/ddos.log 2>&1
cronで15分おきにルール追加w

ちょー過激w
しかし、だんだんCGIに到達するリクエストが減って逝きますなぁw
252か所ブロックするとリクエストが来なくなってしまったわいw

うーむ。
でもこのやり方。
攻撃者のIPアドレスがプロバイダとか広範囲に及ぶと遮断範囲も広くなりすぎるリスクがあるわけですなw

アクセスしてきたIPアドレスのドメイン名をnslookupで取得してみる。

うーむ。西側諸国?w
いや、ただのTorの出口ノードだ。
なんだー、だったらTorのコンソールから出口ノードのアドレスを取得してブロックしたほうが速い。

/somewhere/ddos.sh

#!/bin/sh

cd /somewhere/ddos
../tor_getinfo_ns_all.exp localhost 9051|perl tor_exit_rule.pl

Torの出口ノードのIPアドレスのリストはTorコンソールに問い合わせて超高速に取得できる。 ../tor_getinfo_ns_all.exp

#!/usr/bin/expect -f
set tor_host [lrange $argv 0 0]
set tor_control_port [lrange $argv 1 1]
set timeout 30
spawn telnet $tor_host $tor_control_port
expect "Escape character is '^]'."
send "AUTHENTICATE \"hogehoge\"\r"
expect "250 OK"
send "getinfo ns/all\r"
expect "250 OK"
send "quit\r"
expect eof exit 0
# EOF

取得した出口ノードのIPアドレスからiptablesのブロックルールを生成。

/etc/sysconfig/iptablesにTOR_EXIT_BLOCKの名前の空のチェインを追加。

:TOR_EXIT_BLOCK - [0:0]
-A INPUT -j TOR_EXIT_BLOCK
/somewhere/tor_exit_rule.pl
#!/usr/bin/perl

strict;

#s Fast Guard Running Stable V2Dir Valid
#w Bandwidth=11000
#r Unnamed Kk7pCNHkZxpF8MZwzDCec8mMmNw 92BMohSojV4NTCTh/S3Ro+XQqFE 2016-03-02 19:50:15 93.184.66.227 443 80

# TOR_EXIT_BLOCKチェインを空にする。
system("iptables -F TOR_EXIT_BLOCK");

while (<>) {
        if (/^r /) {
                my @items = split(/ /);
                my $cmd = "iptables -A TOR_EXIT_BLOCK -s ".$items[6]."/32 -j DROP";
                system($cmd);
        }
}

いまいち遅いなぁ。

#!/usr/bin/perl

strict;

my $tor_r;
my $tor_s;
my $tor_w;

my @items;

print "*filter\n";

while (<>) {
    s/\r+\n/\n/g;
    chomp;
    $line = $_;
    if (/^r /) {
        if ($tor_s =~ /Exit/) {
            print "-A TOR_EXIT_BLOCK -s ".$items[6]."/32 -j DROP\n";
        }
        @items = split(/ /, $line);
        $tor_r = $items[6];
    }
    if (/^s /) {
        $tor_s = $line;
    }
    if (/^w /) {
        $tor_w = $line;
        $tor_w =~ s/w Bandwidth=//;
    }
}
print "COMMIT\n";
#!/bin/sh

cd /somewhere/ddos
../tor_getinfo_ns_all.exp localhost 9051|perl tor_exit_rule.pl >tor_exit_rule.txt
iptables -F TOR_EXIT_BLOCK
iptables-restore -n tor_exit_rule.txt
iptables-restore -nの(-n)オプションが重要。
これならiptablesを一瞬で更新できる。

おー、退治完了w

投稿されたコメント:

コメント
コメントは無効になっています。