一昨日、PHP5.4.9とPHP5.3.19が公開されましたが、changelogを読んで驚きました。
Mbstring:mbstring.encoding_translationが有効になっている場合、max_input_varsが有効にならないというのです。これは、hashdos脆弱性の対策が無効になることを意味します。
Fixed bug #63447 (max_input_vars doesn't filter variables when mbstring.encoding_translation = On).
http://www.php.net/ChangeLog-5.php#5.4.9より引用
これは大変だということで、PHP5.4.8とPHP5.4.9で検証してみました。その結果を以下に示します。
mbstring.encoding_translation | ||
Off | On | |
PHP5.4.8 | OK | NG |
PHP5.4.9 | OK | OK |
ご覧のように、確かにPHP5.4.8で、かつmbstring.encoding_translationが有効の場合、max_input_varsのチェックが無効です。これは、hashdos攻撃を受けることを意味しますので、試しにやってみました。多数のhashdosリクエストをPOSTした状態の top コマンドの表示を下記に示します。MaxClientsは50です。
50個のapache2プロセスがすべてhashdosリクエストの処理に占有されています。このリクエスト、1プロセスのみで動作させた場合 5~6分かかるので、50プロセス並行だと4~5時間占有されることになります。この間、新たなリクエストを受け付けることができなくなります。
検証はPHP5.4.8以外にPHP5.4.0でも実施しましたが、PHP5.4.8と同じ結果となりました。おそらく、PHP5.4.8以前のすべてのバージョンでこの問題があると予想されます。
CentOSやUbuntuのPHPパッケージは問題ない
CentOSやUbuntuのyumやapt-getでPHPパッケージを導入した環境でも調べてみましたが、不思議なことに、この問題は再現しませんでした。原因は不明ですが、これらのPHPパッケージでは、max_input_varsの確認方法として、オリジナルとは別の実装が採用されている可能性があります。調査したディストリビューションとPHPパッケージのバージョン、確認結果を下表に示します。少し古いバージョンですがご了承下さい。個別の判定については、後述のチェック用スクリプトをご活用下さい。
Linuxディストリビューション | PHPパッケージバージョン | 結果 |
CentOS release 5.5 | php-5.1.6-27.el5_7.5 | OK |
CentOS release 6.2 | php-5.3.3-3.el6_2.6.i686 | OK |
Ubuntu 10.04.1 LTS | 5.3.2-1ubuntu4.14 | OK |
Ubuntu 12.04 LTS | 5.3.10-1ubuntu3 | OK |
チェック用スクリプト
hashdosの状態を確認するためのスクリプトを作成してみましたので、Webサイトのチェックにご活用下さい。 このスクリプトを任意のファイル名(PHPスクリプトとして実行できる拡張子)でチェック対象Webサーバーに保存して下さい。Webブラウザを用いて、このスクリプトを実行すると、結果が表示されます。JavaScriptを有効にして下さい。チェック終了後はスクリプトを削除して下さい。<?php if (@$_GET['mode'] === 'check') { header('Content-Type: text/plain'); echo (int)count($_POST); exit; } $max_input_vars = ini_get('max_input_vars'); $postnumber = (int)$max_input_vars + 10; if ($max_input_vars === false) { $max_input_vars = 'undefined'; } ?> <html> <head> <title>PHP hashdos checker</title> </head> <body> PHP version : <?php echo htmlspecialchars(phpversion()); ?><br> max_input_vars : <?php echo htmlspecialchars($max_input_vars); ?><br> mbstring.encoding_translation : <?php echo htmlspecialchars(ini_get('mbstring.encoding_translation')); ?><br> <div id='result'></div> <div id='judgment'></div> <script> var n = <?php echo (int)$postnumber; ?>; var data = ''; for (var i = 1; i <= n; i++) { data += i + '=&'; } var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4 && req.status == 200) { var count = req.responseText; document.getElementById('result').appendChild( document.createTextNode('Number of POST parameters : ' + count)); if (count < n) { judgment = 'This web server is NOT vulnerable to hashdos.'; } else { judgment = 'This web server is VULNERABLE to hashdos.'; } document.getElementById('judgment').appendChild(document.createTextNode(judgment)); } } req.open('POST', '?mode=check' ); req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); req.send(data); </script> </body> </html>
いくつか、動作例を下記に示します。
環境 | 結果 |
PHP5.4.8 | PHP version : 5.4.8 max_input_vars : 1000 mbstring.encoding_translation : 1 Number of POST parameters : 1010 This web server is VULNERABLE to hashdos. |
PHP5.4.9 (mbstring.encoding_translation = On) | PHP version : 5.4.9 max_input_vars : 1000 mbstring.encoding_translation : 1 Number of POST parameters : 0 This web server is NOT vulnerable to hashdos. |
PHP5.4.9 (mbstring.encoding_translation = Off) | PHP version : 5.4.9 max_input_vars : 1000 mbstring.encoding_translation : Number of POST parameters : 1000 This web server is NOT vulnerable to hashdos. |
Ubuntu 12.04 LTS 5.3.10-1ubuntu3 | PHP version : 5.3.10-1ubuntu3 max_input_vars : 1000 mbstring.encoding_translation : 1 Number of POST parameters : 1001 This web server is NOT vulnerable to hashdos. |
上記から、興味深いことが分かります。
PHP5.4.9では、mbstring.encoding_translationがOnの時とOffの時で、防御のための挙動が変わります。Offの場合は、変数の数が max_input_varsまで切り詰められます。Onの場合は、POST変数がすべて削除されます。
また、Ubuntu12.04のPHPパッケージを導入している場合、mbstring.encoding_translationに関わりなく(上記には出ていませんが)、max_input_vars + 1 に変数の数が切り詰められます。私の調べた範囲では、LinuxディストリビューションのPHPパッケージはすべてこうなっていて、「LinuxディストリビューションのPHPパッケージはmax_input_varsのチェック方法が異なるのではないか」と思った根拠はこれです。
対策
再現条件がはっきりしないため、上記チェックスクリプトで、脆弱性の確認をお勧めします。対策が必要な場合は、下記の手段があります。- PHPの最新版を導入する(本稿執筆時点でPHP5.4.9、またはPHP5.3.19)
- mbstring.encoding_translation をOffに設定する(可能な場合)
- hashdosの回避策を実装する
- hashdosのリスクを受容する
- Webアプリケーションに対する広範なDoS攻撃手法(hashdos)の影響と対策
- hashdos攻撃をmod_securityで防御する(CentOS+yum編)
- hashdos攻撃をmod_securityで防御する(Ubuntu+apt-get編)
- Cookieによるhashdos攻撃と対策
- ModSecurityをソースからビルドしてhashdos対策に活用する
免責
このセキュリティ情報は予告なしに改訂される場合があります。このセキュリティ情報を適用した結果について徳丸浩およびHASHコンサルティング株式会社は一切の責任を負わず、利用者の利益のために、あるがままの状態で公開するものとします。PR
HASHコンサルティング株式会社では、Webサイトを安全に守るためのセキュリティサービスを提供しています。WAF(Web Application Firewall)による効果的な脆弱性対策(hashdosを含む)や、リスクの評価、対策方法の策定、セキュリティの教育などを提供します。詳しくはお気軽にお問い合わせ下さい。