Category: the Month of PHP Bugs
MOPBの攻撃コードサンプルが削除される
August 13th, 2007Link: http://blog.php-security.org/archives/91-MOPB-Exploits-taken-down.html
ドイツで他人のコンピュータを攻撃するソフトウェアの公開などを禁止する法律が施行されたためMOPBの攻撃コードが削除されました。
ダウンロードリンクは在りますがダウンロードしたファイルの中身は以下のようになっています。
Dear Visitor,
since Friday 10th, August 2007 a new and very troubling law is enforced in germany.
It is no longer legal to create and/or distribute so called hacking tools in germany. This includes port scanners like nmap, security scanners like nessus or simple proof of concept exploits like the MOPB exploits. They are now illegal because someone COULD use them to commit crimes.
Until today I had hoped that our Bundespresident would stop this insane law with a last minute veto, but now it is official and our government has rendered germany more or less defenseless against the threats from outside germany.
Unfortunately our government has been deaf to the warnings from lots of experts that tried to explain how important these so called hacking tools are not only for the current generation of security consultants to do their daily job, but also how important they are for the education of the next generation of researchers and consultants.
If you do not know how to attack, you will never know how to defend yourself.
Yours,
Stefan Esser
オープンソース、商用問わず脆弱性を検査するソフトウェアは多数ありますがこれらの扱いはどうなっているのか興味深いです。
# WatchFireは非合法会社!?なのか、など。
数々のMonth of Bugsプロジェクトによりソフトウェアの脆弱性は公開する事により改善する事が証明されてきました。Stefan氏が指摘しているようにどのように攻撃されるか知らないとどのように防御するのか理解できません。脆弱性を隠せば隠すほど悪人たちに悪用されるリスクが高くなります。法律を作成した方たちは隠せば状況が良くなると勘違いしているのでしょう...
日本の場合も中学生でもできるような単純な攻撃に脆弱なWebサイトが数えきれないほど運用されています。これも法律のせいですね...
私は全ての攻撃コードをダウンロードしているので欲しい方はコメントに書いてください。ニーズがあればどこかに公開します。
MOBPを訳し終えて
April 14th, 2007もう何年か前になりますがStefanさんがPHPプロジェクトへの貢献を始めたころ「整数オーバーフローの修正はセキュリティ脆弱性なのでそのことを明記すべき」と指摘した事がありました。信じがたいかもしれませんが「攻撃可能かどうか分からないし脆弱性でなく普通のバグ修正だ」と主張する開発者がいたためPHPのこの手のヒープオーバーフローセキュリティ修正は「fixed crash」とCVSログに書いてあるだけの場合が多く、NEWSファイルにも記載されない事が当たり前になっていました。
同じく何年も前になりますが、Stefanさんが「PHPのソースディストリビューションのMD5サムをphp.netサイトで公開すべき」と主張した際にも「なぜ?必要ないでしょう」と返す開発者もいました。(公式ミラー、非公式のコピーなどを全く考慮していない発言)幸いMD5サムは必要であると開発者コミュニティで合意が取れたので追加されることになりましたが...
私がregister_globals=offをデフォルトにしては?コード管理の為にリリースブランチを作っては?と提案した場合も合意に至るまでかなり長い議論が必要でした。
万事がこういった状態だったのでセキュリティに対する理解が足りない開発者に対してMOPBは必要だったと考えています。MOPBが行われたことによりPHPプロジェクトがよりセキュリティに対して敏感かつ想像力をもって対処できるようになると思っています。
それにしてもStefanさんの粘り強さは感嘆に値します。この何年間にもわたりセキュリティ意識のギャップが大きい開発者と議論し、正しい意見であるにも関わらずその意見を無視されてきたにも関わらず、諦めなかったことは全てのPHPユーザにとって非常に大きな利益です。
私とPHPのセキュリティについて話をされた事がある方は「PHPを安全に利用するには最新版PHP、それもPHP5系を利用しなければならない」と言っていた事を覚えているかと思います。私は実際に攻撃コードを考案するまでには至りませでしたがMOPBは非常に多くのコード実行脆弱性を明らかにしました。MOPBを日本のユーザにも読みやすいよう翻訳したことによりアップグレードの重要性、正しいセキュリティ対策の重要性を理解して頂けたと思います。改めてMOPBの和訳を快く許可して頂いたStefanさんに感謝します。
MOPBは終わりましたが http://www.php-security.org/ でのアドバイザリが終了した訳ではありません。これ以降のアドバイザリは私のブログでの翻訳は行いませんが、今後もこのサイトには注目は必要です。
MOPB-44-2007:PHP 5.2.0 Memory Manager Signed Comparision Vulnerability
April 14th, 2007Link: http://www.php-security.org/MOPB/MOPB-44-2007.html
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監査に協力していただける場合、私たちに連絡して頂ければ幸いです。
MOPB-43-2007:PHP msg_receive() Memory Allocation Integer Overflow Vulnerabilty
April 13th, 2007Link: http://www.php-security.org/MOPB/MOPB-43-2007.html
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に対しても可能です。
MOPB-42-2007:PHP 5 php_stream_filter_create() Off By One Vulnerablity
April 12th, 2007Link: http://www.php-security.org/MOPB/MOPB-42-2007.html
Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
MOPB-42-2007.php
■リファレンス
なし
■サマリ
php_stream_filter_create()関数は容易にコーディングが行えるようフィルタ名にワイルドカードをサポートしています。フィルタ名が分からずフィルタ名にドットがある場合、それ以降は切り詰められ*が追加されます。この処理はフィルタ名がドットで終了する場合に必要な追加のバイトを考慮していません。この結果php://filter URLにアクセスするとオフバイワン脆弱性が発生します。
■影響するバージョン
PHP 5.2.1未満
■詳細情報
php_stream_fileter_create()関数によってフィルタが作成される際には、最初にフィルタ名のハッシュテーブルが検索され、見つからない場合は要求されたフィルタをサポートするワイルドカードフィルタないか検索します。これは以下のコードにより処理されます。
if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n, (void**)&factory)) {
filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
} else if ((period = strrchr(filtername, '.'))) {
/* try a wildcard */
char *wildname;
wildname = estrdup(filtername);
period = wildname + (period - filtername);
while (period && !filter) {
*period = '\0';
strcat(wildname, ".*");
if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname), (void**)&factory)) {
filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
}
*period = '\0';
period = strrchr(wildname, '.');
}
efree(wildname);
}
この関数はドットでフィルタ名が終了する場合に必要なバイト分を保持していないので、決してフィルタ名がドットで終了しないことを仮定していることは明らかです。この為、ドットで終了するフィルタ名はオフバイワンオーバーフローを発生させ、バッファの最後のバイトの次のアドレスに\0文字を書き込みます。
この脆弱性が攻撃可能かどうかはヒープの実装に大きく依存しています。PHP 5.2.0の新しいメモリマネージャはこの脆弱性の攻撃をリトルエンディアンシステムで可能にしています。
■PoC、攻撃コードまたは再現手順
この脆弱性をテストするには以下のコードを実行します。
<?php
$url = "php://filter/read=OFF_BY_ONE./resource=/etc/passwd";
fopen($url, "r");
?>
このPoCは1バイトのバッファオーバーフローを発生させます。ヒープの実装によってはPHPはクラッシュするかもしれませんし、何事もなかったように実行されるかもしれません。PHP 5.2.0ではビープブロックの長さを保持しているアドレスの下位バイトを上書きするので常にクラッシュします。もしSuhosinパッチを適用している実行している場合、オーバーフロー警告を発生させプロセスを終了します。コード実行を行う攻撃コードは将来このサイトに追加されます。後ほど確認してください。
■備考
この脆弱性がローカルからの攻撃可能な脆弱性と考えないでください。攻撃はphp://filter URLで可能でありallow_url_fopenやallow_url_include設定にはかかわらず攻撃できます。include脆弱性やファイル関数にURLを指定できる場合、リモートからバッファオーバーフローを攻撃できます。
MOPB-41-2007:PHP 5 sqlite_udf_decode_binary() Buffer Overflow Vulnerability
April 11th, 2007Link: http://www.php-security.org/MOPB/MOPB-41-2007.html
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にアップグレード後も脆弱な状態となります。
MOPB-40-2007:PHP imap_mail_compose() Boundary Stack Buffer Overflow Vulnerability
April 10th, 2007Link: http://www.php-security.org/MOPB/MOPB-40-2007.html
Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
MOPB-40-2007.phpの予定
■リファレンス
なし
■サマリ
マルチパートのEメールを作成する為に利用されるPHPのimap_mail_compose()関数は、長すぎるバウンダリ文字列が渡されるとスタックバッファがオーバーフローします。これは任意コードの実行を許します。
■影響するバージョン
PHP 4.4.5未満、PHP 5.2.1未満
■詳細情報
imap_mail_compose()関数はtmpと呼ばれる固定のスタックバッファを利用してマルチパートメールを作成します。
PHP_FUNCTION(imap_mail_compose)
{
...
char tmp[8 * MAILTMPLEN], *mystring=NULL, *t=NULL, *tempstring=NULL;
マルチパートメッセージが作成される場合、最初に入力引数からBOUNDARYが読み込まれサイズチェックなしでsprintfによってスタックバッファにコピーされます。
if (bod && bod->type == TYPEMULTIPART) {
/* first body part */
part = bod->nested.part;
/* find cookie */
for (param = bod->parameter; param && !cookie; param = param->next) {
if (!strcmp (param->attribute, "BOUNDARY")) {
cookie = param->value;
}
}
/* yucky default */
if (!cookie) {
cookie = "-";
}
/* for each part */
do {
t=tmp;
/* build cookie */
sprintf (t, "--%s%s", cookie, CRLF);
これがバッファオーバーフローを許すことは明らかです。
■PoC、攻撃コードまたは再現手順
この脆弱性をテストするには以下のコードを実行します。
このPoCはPHPをクラッシュさせるだけです。しかし、コード実行攻撃は通常通りの手法です。攻撃コードは詳細このサイトに追加されます。後ほど確認してください。
■備考
この脆弱性は08/15のスタックバッファオーバーフローの再現です。
MOPB-39-2007:PHP str_replace() Memory Allocation Integer Overflow Vulnerability
April 9th, 2007Link: http://www.php-security.org/MOPB/MOPB-39-2007.html
Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
MOPB-39-2007.phpの予定
■リファレンス
なし
■サマリ
str_replace()関数が1文字を長い文字列で置換するように呼び出され、その1文字が置換対象の文字列に非常に多く含まれている場合、バッファのサイズが計算される際に整数オーバーフローが発生します。小さすぎるバッファはオーバーフローを引き起こします。
■影響するバージョン
PHP 4.4.5未満、PHP 5.2.1未満
■詳細情報
str_replace()関数が呼ばれる場合、置換対象の文字列の長さによって2つの別の経路でコードを実行します。1文字の検索文字列はより効率的に処理するために別の関数で処理されます。しかし、より効率的なコードは整数オーバーフロー脆弱性を含んでいます。
Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
Z_STRVAL_P(result) = target = emalloc(Z_STRLEN_P(result) + 1);
Z_TYPE_P(result) = IS_STRING;
例えば、char_countとto_len両方が65537以上の場合、32ビットのカウンタがオーバーフローするのは明らかです。このため、emalloc()によって十分なメモリが割り当てられません。置換が行われる際にバッファーオーバーフローを引き起こします。攻撃を成功させるには目的のバッファは、オーバーフローで上書きできコピーがクラッシュを起こす前に終了するよう、置換対象の文字列の前に配置されなければなりません。
■PoC、攻撃コードまたは再現手順
この脆弱性をテストするには以下のコードを実行してください。
<?php
str_replace("A", str_repeat("B", 65535), str_repeat("A", 65538));
?>
このPoCはPHPをクラッシュさせるだけです。この脆弱性を利用したコード実行攻撃は将来このサイトい追加されます。後ほど確かめてください。
■備考
解説した問題はPHP 4.4.5, PHP 5.2.1で修正されました。しかし、PHP 4.4.5, PHP 5.2.1より前のセキュリティフィックスは壊れており、同じ個所でオフバイワンオーバーフローに脆弱でした。置換文字を別の文字に置き換える場所で発生します。
新しくリリースされたPHP 4.4.6はオフバイワン脆弱性が修正されていますが、PHP 5.2.1には修正がありません。
MOPB-38-2007:PHP printf() Family 64 Bit Casting Vulnerabilities
April 8th, 2007Link: http://www.php-security.org/MOPB/MOPB-38-2007.html
Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
MOPB-37-2007.phpの予定
■リファレンス
なし
■サマリ
printf()関数と類似の関数に利用されるヘルパー関数は符号なしの63ビット整数を返します。しかし、内部的には32ビット整数の結果が保存されています。32ビットへのトランケートにより、結果の整数は、異なる実行パスによって呼び出されると、検出されずに負の値になることがあります。この動作により2種類の攻撃可能なメモリ破壊が可能となります。
■影響するバージョン
PHP 4.4.5未満、PHP 5.2.1未満
■詳細情報
printf()と類似の関数は内部的にフォーマット文字列をパースし、フォーマット既述子を処理する、php_formatted_print()関数を利用しています。この関数は通常のフォーマット文字列、$修飾子により既述子の番号を選択可能とし幅と精度を指定できます。この関数は正の値、幅、精度のみ受け付けます。これらの3つの値はphp_sprintf_getnumber()関数によって取り出されます。
inline static long
php_sprintf_getnumber(char *buffer, int *pos)
{
char *endptr;
register long num = strtol(&buffer[*pos], &endptr, 10);
register int i = 0;
if (endptr != NULL) {
i = (endptr - &buffer[*pos]);
}
PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
*pos += i;
return num;
}
残念ながら、内部的にはこの関数は64ビットシステム上では64bit幅のlong型として動作します。呼び出し側のコードは番号は数字で始まりマイナス符号で始まらず、結果が常に正のlong数値になるようにしています。しかし、既述子の数、幅と精度はintとして保存され、64ビットから32ビットへの変換は負の値になる場合があります。
これは2つの問題を発生させます。はじめに、記述子の数は最大値のチェックだけ行い、負の値はありえないと仮定し、正しく処理していません。これにより64ビットシステムでは任意のメモリアドレスを参照可能としています。この問題は任意のメモリアドレス情報の漏えいか攻撃可能なメモリ破壊をもたらします。
2つ目の問題はこのキャスト脆弱性によって"s"フォーマット記述子php_sprintf_appendstring()を利用する関数に発生します。幅と-1の精度が指定されるとバッファ位置から1つ前の位置となります。このパターンを繰り返すことにより、ポインタの位置を実際のヒープのバッファより前の設定できます。内部のバッファのポインタがヒープの制御構造に位置するとフォーマット文字列の文字で書きかえることができます。
両方の攻撃経路はコード実行を可能にしますが、2つめの経路は簡単かつ確実に、リモートから、攻撃できます。
C言語のフォーマット文字列脆弱性と異なりPHPのフォーマット文字列脆弱性は64bitシステムでのみ攻撃でき、少なくともフォーマット文字列の後の引数1つがprintf()か類似の関数であることです。
■PoC、攻撃コードまたは再現手順
POC will be released during the next week
■備考
解説した問題は我々が問題を報告した後、PHP開発者によってPHP 4.4.5とPHP 5.2.1で修正され、新たに生まれたPHPアプリケーションのフォーマット文字列脆弱性は既に消滅したはずです。
MOPB-37-2007:PHP iptcembed() Interruption Information Leak Vulnerability
April 7th, 2007Link: http://www.php-security.org/MOPB/MOPB-37-2007.html
Stefanさんの承諾を得て日本語訳を公開しています。このブログの「the Month of PHP Bugs」カテゴリでMOPBの翻訳ページを一覧できます。分かりやすいように意訳できる部分は意訳します。厳密に原文の通り訳していないので正確性を重視される方は原文をご覧ください。
■クレジット
発見者:Stefan Esser
攻撃コード:Stefan Esser
■PoCまたは攻撃コード
MOPB-37-2007.php
■リファレンス
なし
■サマリ
関数がリファレンスを受け入れる場合(デフォルト設定で受け入れるようになっている)悪意のあるユーザ定義エラーハンドラで関数が既に実行を開始しパラメータを変更した後に割り込みが可能です。このアドバイザリは関数を使って任意のメモリアドレスを読み込む例となっています。iptcembed()関数はこの種の脆弱性の例で、攻撃者は任意のヒープメモリのリークに利用できます。
■影響するバージョン
PHP 4.4.6以下、PHP 5.2.1以下
■詳細情報
iptcembed()関数が呼ばれると、3つの引数が定義されている形式に変換されます。
if (zend_get_parameters_ex(3, &iptcdata, &jpeg_file, &spool_flag) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(iptcdata);
convert_to_string_ex(jpeg_file);
convert_to_long_ex(spool_flag);
spool = Z_LVAL_PP(spool_flag);
残念ながらconvert_to_*関数は特定の条件でエラーを発生させます。例えば、配列をjpeg_fileとして渡す、spool_flag引数にオブジェクトを渡すなどです。このような状況が発生するとユーザ定義エラーハンドラは、はじめにiptcdata保持する変数をintにキャストし、その後longに値とします。これにより文字列と間違えられ、文字列の長さを保持するメモリ位置のlong値で指定された長さとしたZVALを作成できます。
簡単なトリックで任意のメモリブロックをリークされる事ができるのは明らかです。
■PoC、攻撃コードまたは再現手順
添付の攻撃コードが実行されると0x08048000から256バイトリークします。通常のLinuxシステムはこのアドレスに現在実行中のプログラムのELFヘッダが保存されています。
memdump
---------00000000: 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 02 ELF.............
00000010: 00 03 00 01 00 00 00 d0 72 08 08 34 00 00 00 bc ........r..4....
00000020: 1d b7 00 00 00 00 00 34 00 20 00 08 00 28 00 26 .......4. ...(.&
00000030: 00 23 00 06 00 00 00 34 00 00 00 34 80 04 08 34 .#.....4...4...4
00000040: 80 04 08 00 01 00 00 00 01 00 00 05 00 00 00 04 ................
00000050: 00 00 00 03 00 00 00 34 01 00 00 34 81 04 08 34 .......4...4...4
00000060: 81 04 08 13 00 00 00 13 00 00 00 04 00 00 00 01 ................
00000070: 00 00 00 01 00 00 00 00 00 00 00 00 80 04 08 00 ................
00000080: 80 04 08 60 af 3a 00 60 af 3a 00 05 00 00 00 00 ...`.:.`.:......
00000090: 10 00 00 01 00 00 00 00 b0 3a 00 00 30 3f 08 00 .........:..0?..
000000a0: 30 3f 08 ac 84 02 00 cc 19 04 00 06 00 00 00 00 0?..............
000000b0: 10 00 00 02 00 00 00 14 b0 3a 00 14 30 3f 08 14 .........:..0?..
000000c0: 30 3f 08 50 01 00 00 50 01 00 00 06 00 00 00 04 0?.P...P........
000000d0: 00 00 00 04 00 00 00 48 01 00 00 48 81 04 08 48 .......H...H...H
000000e0: 81 04 08 20 00 00 00 20 00 00 00 04 00 00 00 04 ... ... ........
000000f0: 00 00 00 50 e5 74 64 98 ae 3a 00 98 2e 3f 08 00 ...P.td..:...?..
■備考
この分類の脆弱性はZendエンジンのアーキテクチャ上の脆弱性です。我々はこの例のような割り込みバグが
直ぐに修正されるとは考えていません。allow_call_time_pass_referenceを無効にすることはこのアドバイザリの攻撃コードを無効化させるには役立ちます。しかし、リファレンスや別のデータ構造が渡される場合、類似する「関数割り込み攻撃」から守ることはできません。


