“the Month of PHP Bugs”をできるだけ多くの方が読めるように、Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者: Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
不必要
■リファレンス
なし
■サマリ
64ビットシステムの場合、ユーザが送信したシリアライズされた文字列は厳しい無限ループがzend_hash_init()で発生しCPUリソースを使い切ってしまう。
■影響するバージョン
PHP 4.4.5/5.1.1以下
■詳細バージョン
PHP 4.3.11がリリースされる前にunserialize関数に負の配列要素数をシリアル化した文字列に設定し処理させるとzend_hash_init()内で無限ループが発生し攻撃可能であることが発見されていました。
この問題はzend_hash_init()関数に値が渡される前に負の整数である場合にエラーを発生させることにより修正されました。負の整数がzend_hash_init()に渡されると、整数の左シフトオーバーフローが発生し無限ループに陥りました。
しばらく経ってから、幾つかの変数がintからlong型に変更されたため64ビットシステム上のunserialize関数に問題が発生しました。残念ながらzend_hash_init()はint型で処理をしていました。この為、unserialize関数からは下位32ビットの値のみzend_hash_init()に渡されていました。
これにより64ビットシステム上では32ビットの負の整数は正の整数の範囲内となり、負の要素数に対する防御は機能しなくなりました。
■PoC、攻撃コードまたは再現手順
64ビットシステム上で再現するには次のコードを実行します。
<?php unserialize("a:2147483649:{"); ?>
■備考
PHP4.4.5とPHP5.1.2以降でこの脆弱性は修正されています。
スクリプトはmax_execution_timeを超えると実行を停止する事にも留意してください。しかし、この値が30秒に設定されている場合、10リクエストで10の無限ループを発生させると、5分間100%のCPUロードに陥ります。