MOPB-29-2007:PHP 5.2.1 unserialize() Information Leak Vulnerability

3月 27, 2007 Computer, Development, Programming
(Last Updated On: 2018年8月16日)

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

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

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

■リファレンス
なし

■サマリ
PHP 5.2.1から追加されたS: データ型シリアライズフォーマットは完全に壊れています。エスケープされた文字列を処理するための新機能ですが動作しないだけでなくヒープメモリ情報の漏えいを可能にしています。

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

■詳細情報
新たにPHP 5.2.1からS: データタイプがunserialize()に追加されました。この機能は将来リリースされるPHP6とシリアライズされたデータの互換性を保つために追加されました。データ型自体は簡単なエスケープバイトがサポートされている以外は通常のs: データ型と同じです。以下の文字列がS:データ型の例です。

S:10:”\55\44APXY”

残念ながらこれらのエスケープされた文字列のアンシリアライズ処理は完全に壊れており、公表されているように全く働きません。

アンシリアライズ処理が行われた場合、6バイトの文字列を返すさず、上記の例は常に10バイトと返すかエラーとなります。アンシリアライズ処理が10バイトの入力を処理した時に終了せず、10バイトの出力が書かれた時に終了するからです。

次のバイトが”(ダブルクオート)文字である場合、最後の出力バイトから“(ダブルクオート)までのメモリ情報をリークします。

■PoC、攻撃コードまたは再現手順
添付の攻撃コードが実行されるとヒープメモリ情報をリークさせるようなデータをPHP変数に代入してリーク可能なメモリレイアウトを作り、16進数ダンプを出力します。成功した場合、メモリダンプはメモリクッキーとハッシュバケットをメモリヘッダ付きで出力します。このヒープのアドレス(または秘密であるべきクッキー情報)から別の攻撃を行うことが可能になります。

Heapdump
———

00000000: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000010: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000020: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000030: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000040: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000050: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000060: 61 61 61 61 22 00 00 00 00 63 da 58 21 fd 00 00 aaaa”….c.X!…
00000070: 00 45 01 00 00 26 bb b9 7e ca 00 00 00 b0 72 91 .E…&..~…..r.
00000080: b7 18 6f 91 b7 a0 73 91 b7 00 00 00 00 00 00 00 ..o…s………
00000090: 00 00 00 00 00 22 22 22 22 22 22 22 22 22 22 22 …..”””””””””””
000000a0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
000000b0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
000000c0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
000000d0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
000000e0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
000000f0: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
00000100: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
00000110: 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 “”””””””””””””””
00000120: 22 22 22 22 22 22 22 22 22 22 22 22 .. .. .. .. “”””””””””””….

■備考
我々にとっては全くテストされていないコードがPHPリリースに含まれてしまったことは謎です。S: データ型は全く動作せず、情報リーク攻撃だけにしか利用できません。最も簡単なテストでこれが壊れていることを発見できるはずです。

さらに、PHP開発者がシリアライズデータがPHP5とPHP6と互換性を持つような機能を追加したことも謎です。unserialize()にセキュリティ脆弱性が発見されるたびにユーザは開発者から「ユーザからのデータ対してunserialize()を使ってはならないものだ」にと言われます。(訳注:マニュアルには書いてないですが実際にそう言っている開発者もいます。unserialize()はユーザが送信したデータに対して利用しない方が安全なのは確かですが、壊れた実装が一番問題です)ユーザデータに使ってはならない関数であれば、なぜデータ交換を簡単にする為(つまりユーザからの入力データに対して)の機能を実装したのでしょうか?

投稿者: yohgaki