slowlorisの攻撃とその対策方法

たまにslowlorisによる攻撃について聞くようになった。
自分のとこのapacheに攻撃してみてみたり、対策方法を試してみたのを書いておく。

slowlorisツールの取得

まずはツールを落としてくる。
ツールは下記にあるので拝借します。

▼ ha.kers
http://ckers.org/slowloris/

$ wget http://ha.ckers.org/slowloris/slowloris.pl

モジュールがないのでいれます。
必要なモジュールは上記にページに記載されてます。

$ perl -MCPAN -e 'install IO::Socket::INET'
$ perl -MCPAN -e 'install IO::Socket::SSL'

んで、早速実行

$ perl slowloris.pl -num 1000 -port 80 -dns localhost

やってみると攻撃開始直後からマジで繋がらなくなる。


色々と見てみる

■ 通常
$ netstat -an | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN

■ 攻撃時
$ netstat -an | grep 80 | tail
tcp6     226      0 127.0.0.1:80            127.0.0.1:39837         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39539         FIN_WAIT2  
tcp6       0      0 127.0.0.1:80            127.0.0.1:39679         ESTABLISHED
tcp6     226      0 127.0.0.1:80            127.0.0.1:39904         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39864         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39732         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39856         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39636         ESTABLISHED
tcp6       0      0 127.0.0.1:80            127.0.0.1:39628         FIN_WAIT2  
tcp6     226      0 127.0.0.1:80            127.0.0.1:39932         ESTABLISHED
表示が多すぎるので数だけ
$ netstat -an | grep 80 | wc -c
107680

アクセスログには攻撃中には何も記載されない。
apacheが返答できない状態になった上で大量に接続されていることで止まっているようだ。
聞いたところだと、3way handshakeのタイミングで大量パケットを送っているとかいないとか。
回線速度が極端に遅い端末から大量にアクセスされても同じ事が現象が起きるらしいが
HTTPリクエストまで辿り着く前に大量にスレッドが消費されて止まるようだ。

対策: Reverse Proxy

対策としてReverseProxyに3way handshakeを行わせ、
HTTPリクエストをapacheが処理を行う構造にすれば問題ないらしいので試してみる。

■ インストール

$ sudo apt-get install nginx

■ 設定

一応バックアップ
$ sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.back
んで編集
$ sudo vim /etc/nginx/nginx.conf

ロードバランサーみたく動かしたりキャッシュもたせたり色々できるらしいんだけど、
今回はリクエストを流すだけ。
設定内容は下記の感じ。
わからないこと多いから多分足りてないが動くには動く。

user www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
    # multi_accept on;
}

http {
    include       /etc/nginx/mime.types;

    access_log  /var/log/nginx/access.log;

    sendfile on;
    keepalive_timeout 65;

    server {
        listen 8080;
        server_name localhost;

        location / {
            proxy_pass http://127.0.0.1;
        }  
    }
}

■ 再起動

$ sudo /etc/init.d/nginx configtest
Testing nginx configuration: nginx.
$ sudo /etc/init.d/nginx restart
Restarting nginx: nginx.

起動スクリプトがなかった場合は下記から。
▼ Nginx 起動スクリプト
http://wiki.nginx.org/InitScriptsJa

8080ポートでアクセスしてもちゃんと動いているのでOK。
本来ならapache側を8080とか別のポートにして、
nginxのポートを80にする方が良いと思う。

■ 攻撃してみる

$ perl slowloris.pl -num 1000 -port 8080 -dns localhost

おお!!問題なくページが表示される!

ほかも見てみよう

攻撃開始直後
$ netstat -an | grep 8080 | wc -l
2001

攻撃開始から数分後
$ netstat -an | grep 8080 | wc -l
1

攻撃中2000コネクションぐらいまで行っていたが、少し時間が経つと1まで落ちた。
ページも確実にアクセスできるしこれで対策としては良さそうだ。