MOPB-44-2007:PHP 5.2.0 Memory Manager Signed Comparison Vulnerability

(Last Updated On: )

Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。

■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser

■PoCまたは攻撃コード
MOPB-37-2007.php

■リファレンス
なし

■サマリ
PHP 5.2.0から導入された新しいZendのメモリマネージャは間違って数値を符号付き整数にキャストして比較しています。これにより非常に大きなメモリ確保は負の値となり、最小のメモリしか確保されません。この脆弱性はPHPの中に攻撃可能な多くのバッファオーバーフローを引き起こします。例えば、PHPのHTTP SOAPクライアントはこの脆弱性によりリモートから攻撃可能です。

■影響するバージョン
PHP 5.2.0

■詳細情報
emalloc()関数によってメモリが割り当てられる際に、新しいZendメモリマネージャは内部の_zend_mm_alloc_int()関数でリクエストを処理します。_zend_mm_aloc_int()関数ははじめにZEND_MM_TRUE_SIZEマクロによって実際にリクエストされたメモリブロックの大きさを決定します。これは以下のコードで行われています。

static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ...)
{
    size_t true_size, best_size = 0x7fffffff;
    zend_mm_free_block *p, *end, *best_fit = NULL;

    true_size = ZEND_MM_TRUE_SIZE(size);

    The macro expands to

    (((long)size<(long)ZEND_MM_MIN_SIZE)?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE):
    (ZEND_MM_ALIGNED_SIZE(size+ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)))

理由は不明ですがこのコードの作者は比較の前にsizeを符号付きlongにキャストしています。これにより非常に大きなメモリブロックのリクエストは通常はメモリ不足の状態になり、メモリ不足の場合は0バイトのメモリが要求されたように処理されます。

これにより多くの異なる個所のPHPコードが攻撃可能になります。メモリが確保できない場合通常の状態ではスクリプトの実行が停止されるべきですが、小さすぎるメモリブロックが確保され戻されるからです。

■PoC、攻撃コードまたは再現手順
我々はこの脆弱性は非常に危険な問題であると判断しているので、PoCの公開は控えます。HTTP SOAPクライアントに対するリモート攻撃コードPoCは作成済みです。

■備考
この非常に危険な脆弱性がMonth of PHP Bugsの最後です。我々は約束した問題の調査行い、新しい発見があった場合はアドバイザリを更新します。しかし、新しいバグを毎日公開するのはこれで終わりです。PHPのような大きさのコードに対する監査プロジェクトは数日で行えるようなものではありませんし、新しいコードはPHPのソースツリーに毎日追加されているので、MOPBは数ヵ月後にまた再開されるかもしれません。私たちは現時点でのすべてのPHPのセキュリティ問題を発見したと考えてはいません。反対にPHPにはまだ公開されていない脆弱性があります。

我々の提案はまだ有効です。我々によって行われるもし別のPHP監査に協力していただける場合、私たちに連絡して頂ければ幸いです。

投稿者: yohgaki