MOPB-22-2007:PHP session_regenerate_id() Double Free Vulnerability

(Last Updated On: 2018年8月16日)

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

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

■PoCまたは攻撃コード
MOPB-22-2007.php
http://www.php-security.org/MOPB/code/MOPB-22-2007.php

■リファレンス
なし

■サマリ
新しいセッションIDを生成するsession_regenerate_id()関数は、セッションIDの生成コードを呼ぶ前に既に、解放済みの前のポインタをクリアしていません。セッションID生成コードでエラーが発生するとダブルフリーが発生します。この脆弱性はローカルでは簡単に攻撃可能で、リモートからの攻撃も可能となる場合があります。

■影響するバージョン
PHP 5.2.1以下。 PHP4はリモート攻撃が可能だとする仮定が成立する場合にのみ影響する。(追加情報を提供します)

■詳細情報
session_regenerate_id()関数ははじめに古いセッションIDを解放します。その直後にセッションID生成コードによって生成された新しい値を代入します。

PHP_FUNCTION(session_regenerate_id)
{

if (PS(id)) {

efree(PS(id));
}

PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);

PS(send_cookie) = 1;
php_session_reset_id(TSRMLS_C);

RETURN_TRUE;
}
RETURN_FALSE;
}

しかし、この代入はアトミックに行われず、例えばmemory_limit制限などにより、割り込みが可能です。さらに、PHPの設定によっては、生成コードは割り込みを可能とするPHPエラーを発生させます。

PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS)
{

switch (PS(hash_func)) {

default:
php_error_docref(NULL TSRMLS_CC, E_ERROR, “Invalid session hash function”);
efree(buf);
return NULL;
}

if (PS(hash_bits_per_character) < 4
|| PS(hash_bits_per_character) > 6) {
PS(hash_bits_per_character) = 4;

php_error_docref(NULL TSRMLS_CC, E_WARNING, “The ini setting hash_bits_per_character…”);
}

この為、悪意のあるユーザ定義エラーハンドラを利用してローカルから攻撃するのは非常に簡単です。このハンドラが呼ばれた時、前のセッションIDが配置された同じ場所にハッシュテーブルが割り当てられます。ユーザエラーハンドラが終了する際にPHPは上書きされたハッシュテーブルを解放し、攻撃者のコードを実行します。

■PoC、攻撃コードまたは再現手順
添付の攻撃コードを実行すると、substr_compare()関数の情報漏えい脆弱性を利用してシェルコードのアドレスを決定して実行します。

■備考
この脆弱性をローカルから攻撃するのは非常に簡単です。しかし、セッションIDの生成中にリクエストが終了する場合にもダブルフリーが発生します。例えば、セッションIDの生成中にmemory_limit制限に達した場合などにリクエストの終了が発生します。

リモートからの攻撃は可能に思えますが非常に難しいでしょう。この仮定が正しいか将来調査するかもしれません。

投稿者: yohgaki