はじめに
既に当ブログで報告の通り、hashdosと呼ばれる攻撃手法が公表されています。HTTPリクエストのパラメータ名に対するハッシュ値を故意に同一にした(衝突させた)ものを多数(数万程度)送信することにより、Webサーバーを数分程度過負荷にできるというDoS攻撃手法です。先の記事でも説明しているようにPOSTパラメータ(HTTPリクエストボディ)に多数のパラメータを仕込む攻撃が典型的ですが、POSTパラメータ以外のパラメータを用いた攻撃についても検討しておかないと、防御漏れの可能性が生じます。
そこで、POSTパラメータ以外を用いた攻撃方法について検討します。
POST以外に多数のパラメータを仕込めるか
POST以外に多数のパラメータを仕込む場所があるでしょうか。候補となるのは、以下と考えられます。括弧内は、PHPの該当変数です。- URLのクエリ文字列($_GET)
- HTTPリクエストヘッダ($_SERVER)
- Cookie($_COOKIE)
リクエストヘッダ($_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) {Cookie bも受け入れられてはいますが、改行のところでbの前にゴミの文字列が入っています。これは、hashdos攻撃に悪影響があります。
["a"]=>
string(1) "1"
[",_b"]=>
string(1) "2"
}
以下のリクエストではどうでしょうか。セミコロンを先頭に持ってきています。
GET /cookie.php HTTP/1.0以下のレスポンスが返ります。
Cookie:;a=1
Cookie:;b=2
array(2) {こんどは、a, bともに名前の方にゴミはありませんが、aの値側にゴミが入りました。しかし、hashdos攻撃ではキー(パラメータ名)のみが問題になるので、攻撃には支障ありません。すなわち、PHPは複数のCookieヘッダを受け入れ、hashdos攻撃に悪用可能であると予想されます。
["a"]=>
string(3) "1, "
["b"]=>
string(1) "2"
}
また、前述の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;1行目で、&をセミコロン「;」に全て変換します。その上で、先頭から8180文字以内のセミコロンで終わる部分文字列を探して切り出します(3行目)。切り出した文字列は、Cookieヘッダして出力しています(4行目)。Apacheのデフォルトの制限に従い、Cookieヘッダは100個以下となるように制限しています。
2: for (my $i = 0; $i < 100 && length($a) > 0; $i++) {
3: $a =~ s/^(.{1,8180}\;)//;
4: print "Cookie:;$1\n";
5: }
試してみる
このようにして作成したCookie用PoCをPHPスクリプトにリクエストしてhashdos攻撃をしてみました。リクエストの送信には、Burp Suiteに含まれるRepeaterというツールを用いました。結果は以下の通りです。
- Cookie数:38166個
- 実行時間:約4分半
対策
hashdos攻撃に対する従来の対策のうち、リクエストボディのサイズやPOSTパラメータの個数を制限する回避策は、Cookieによるhashdos攻撃には効果がありません。一方、以下は効果があります。- hashdos対策版のパッチを適用する(PHPの場合は5.3.9にバージョンアップしてmax_input_varsを設定する。デフォルト=1000のままでもよいが、小さいほど影響を受けにくい)
- リクエストの処理時間を制限する(PHPの場合はmax_input_timeを小さな値にする)
- suhosinパッチによりCookieの個数を制限する(デフォルトの最大数は100)
まとめ
Cookieによるhashdos攻撃について検討しました。理論的にCookieによるhashdos攻撃が可能であることを示した後、PoCを作成して攻撃が成立することを確認しました。POSTパラメータを用いた攻撃への対処が、Cookieによる攻撃にも有効とは限らないので注意が必要です。
[PR]
hashdosやApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
「安全なWebアプリケーションの作り方」DRMフリーのPDFによる電子版もあります。
0 件のコメント:
コメントを投稿