2012年1月19日木曜日

Cookieによるhashdos攻撃と対策

このエントリでは、Cookieを用いたhashdos攻撃の可能性について検討し、実証結果と対策について報告します。

はじめに

既に当ブログで報告の通り、hashdosと呼ばれる攻撃手法が公表されています。HTTPリクエストのパラメータ名に対するハッシュ値を故意に同一にした(衝突させた)ものを多数(数万程度)送信することにより、Webサーバーを数分程度過負荷にできるというDoS攻撃手法です。
先の記事でも説明しているようにPOSTパラメータ(HTTPリクエストボディ)に多数のパラメータを仕込む攻撃が典型的ですが、POSTパラメータ以外のパラメータを用いた攻撃についても検討しておかないと、防御漏れの可能性が生じます。
そこで、POSTパラメータ以外を用いた攻撃方法について検討します。

POST以外に多数のパラメータを仕込めるか

POST以外に多数のパラメータを仕込む場所があるでしょうか。候補となるのは、以下と考えられます。括弧内は、PHPの該当変数です。
  • URLのクエリ文字列($_GET)
  • HTTPリクエストヘッダ($_SERVER)
  • Cookie($_COOKIE)
クエリ文字列($_GET)については、URLの長さの条件、あるいはHTTPリクエストラインの制限に引っかかります。Apacheの場合リクエストラインの制限はLimitRequestLine ディレクティブにより定義され、デフォルト値は8190バイトです。PHPに対するhashdosのPoCのサイズは約1.4メガバイトですから、8190バイトの制約では攻撃には至らないと考えられます。hashdosによる演算時間は、ハッシュ値の一致するパラメータ数の自乗に比例するためです。
リクエストヘッダ($_SERVER)の最大数は、Apacheの場合、LimitRequestFields ディレクティブで定義され、デフォルト値は100です。前述のPoCのパラメータ数は65536ですから、100という制限ではまったく攻撃には至らないと考えられます。
ということで、攻撃の余地が残るパラメータはCookieに絞られました。

Cookieによるhashdosの可能性

多数のCookieを用いたhashdos攻撃の可能性はどうでしょうか? などと書くと、RFC上のCookie数の制限を思い浮かべる方がおられるかもしれませんが、hashdosは能動的攻撃ですので、WebサーバーがどれだけのCookieを受け入れる実装になっているかに依存します。ブラウザの制限やRFC上の制限は関係ありません。
通常、Cookieは単一のCookieヘッダにより送信するので、HTTPリクエストヘッダ一つあたりのバイト数に制約されます。Apacheの場合、LimitRequestFieldSize ディレクティブにより定義され、デフォルト値は8190です。クエリ文字列の場合と同じサイズですので、このままではhashdos攻撃はできません。
しかし、複数のCookieヘッダが使えるとしたら話は変わります。最大100のCookieヘッダが使えることになり、8190×100=約800Kバイトが攻撃に使えることになります。これは攻撃には十分なサイズです。

PHPは複数のCookieヘッダを受け入れる

PHPが複数のCookieヘッダをどのように処理するかを以下のPHPスクリプトcookie.phpにより検証します。このスクリプトにはXSS脆弱性があるので、検証環境で試してください。
<?php
  var_dump($_COOKIE);
?>
以下のリクエストに対して
GET /cookie.php HTTP/1.0
Cookie: a=1;
Cookie: b=2;
以下のレスポンスが返ります。
array(2) {
  ["a"]=>
  string(1) "1"
  [",_b"]=>
  string(1) "2"
}
Cookie bも受け入れられてはいますが、改行のところでbの前にゴミの文字列が入っています。これは、hashdos攻撃に悪影響があります。
以下のリクエストではどうでしょうか。セミコロンを先頭に持ってきています。
GET /cookie.php HTTP/1.0
Cookie:;a=1
Cookie:;b=2
以下のレスポンスが返ります。
array(2) {
  ["a"]=>
  string(3) "1, "
  ["b"]=>
  string(1) "2"
}
こんどは、a, bともに名前の方にゴミはありませんが、aの値側にゴミが入りました。しかし、hashdos攻撃ではキー(パラメータ名)のみが問題になるので、攻撃には支障ありません。すなわち、PHPは複数のCookieヘッダを受け入れ、hashdos攻撃に悪用可能であると予想されます。
また、前述のPoCは、パラメータ名がパーセントエンコードされています。Cookieの場合、パーセントエンコードは必須ではありませんが、PHPの場合、名前・値とも受け取ったCookieをパーセントデコードします。すなわち、既存のPoCがCookieにも流用できることになります。

Cookieを用いたhahsdos攻撃ようのリクエストを作成する

ここまで検討したので、Cookieを用いたhashdos攻撃が成立するか、実際に試してみましょう。
POSTパラメータ用のPoCデータは、a=&b=&c=...という形式になっています。これを;a=;b=;c=...という形に変形した上で、8190バイトの制限内で、複数のCookieヘッダに切り分ける必要があります。
この処理をPerlスクリプトとして作成しました。以下に主要部分を示します。変数$aにPOSTパラメータ用のPoCデータが入っている想定です。
1: $a =~ s/&/;/g;
2: for (my $i = 0; $i < 100 && length($a) > 0; $i++) {
3:   $a =~ s/^(.{1,8180}\;)//;
4:   print "Cookie:;$1\n";
5: }
1行目で、&をセミコロン「;」に全て変換します。その上で、先頭から8180文字以内のセミコロンで終わる部分文字列を探して切り出します(3行目)。切り出した文字列は、Cookieヘッダして出力しています(4行目)。Apacheのデフォルトの制限に従い、Cookieヘッダは100個以下となるように制限しています。

試してみる

このようにして作成したCookie用PoCをPHPスクリプトにリクエストしてhashdos攻撃をしてみました。リクエストの送信には、Burp Suiteに含まれるRepeaterというツールを用いました。
結果は以下の通りです。
  • Cookie数:38166個
  • 実行時間:約4分半
hashdos攻撃の最中はCPU使用率は99%以上となりました。DoS攻撃の成功です。

対策

hashdos攻撃に対する従来の対策のうち、リクエストボディのサイズやPOSTパラメータの個数を制限する回避策は、Cookieによるhashdos攻撃には効果がありません。一方、以下は効果があります。
  • hashdos対策版のパッチを適用する(PHPの場合は5.3.9にバージョンアップしてmax_input_varsを設定する。デフォルト=1000のままでもよいが、小さいほど影響を受けにくい)
  • リクエストの処理時間を制限する(PHPの場合はmax_input_timeを小さな値にする)
  • suhosinパッチによりCookieの個数を制限する(デフォルトの最大数は100)
また、WAFによりCookieの個数を制限できれば、攻撃を回避できます。先のエントリで紹介した方法では、Cookieの個数は制限されないため、以下のエントリに追記をしておきましたので参照ください。


まとめ

Cookieによるhashdos攻撃について検討しました。理論的にCookieによるhashdos攻撃が可能であることを示した後、PoCを作成して攻撃が成立することを確認しました。
POSTパラメータを用いた攻撃への対処が、Cookieによる攻撃にも有効とは限らないので注意が必要です。



[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。


0 件のコメント:

コメントを投稿

フォロワー