# php_stream_url_wrap_http_ex() type-confusion vulnerability

PHP's http fopen wrapper caches a pointer to $http_response_header, which a stream notification callback can retype to a string, causing type confusion and potential RCE.

- Payout: hidden
- Severity: high
- Program: Internet Bug Bounty
- Found by: mongo
- Disclosed: 2015-04-14
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/73247
- Library page: https://bugbountylibrary.com/r/h1%3A73247
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:high tech:php technique:source-review vuln:memory-corruption vuln:rce

**Target:** ext/standard/http_fopen_wrapper.c php_stream_url_wrap_http_ex()
**Root cause:** php_stream_url_wrap_http_ex() stores a raw pointer to the $http_response_header zval in the active symbol table and reuses it without re-validating its type; a user stream notification callback can overwrite that variable with a string mid-execution.
**Steps:**
1. Register a stream context notification callback via `stream_context_set_params($ctx, array("notification" => "stream_notification_callback"))`.
2. In the callback, on `STREAM_NOTIFY_REDIRECTED`, set `$GLOBALS['http_response_header'] = "aaaa...\0\0\0\0";` to retype it to a string.
3. Call `file_get_contents("http://php.net/get-involved", false, $ctx)` against any URL that triggers an HTTP redirect.
4. php_stream_url_wrap_http_ex() later does `zend_hash_next_index_insert(Z_ARRVAL_P(response_header), ...)` on the now-string zval, causing type confusion.
**How found:** Code reading of http_fopen_wrapper.c: noticed the function grabs a pointer to the symbol-table variable and assumes it stays an array across the whole execution, then realized stream notifications fire mid-function and can mutate that variable.
**Exploitation:** Attacker controls the notification callback (e.g. via a library or app that passes user-influenced stream context params) and retypes $http_response_header to a crafted string; the subsequent array insert on a string zval yields memory corruption, historically leading to arbitrary code execution.
**Insight:** When a function caches a pointer into the active symbol table and user callbacks (stream notifications, error handlers, autoloaders) can run mid-execution, the variable can be retyped or unset — look for missing zval_add_ref() and type re-validation at each use.

