|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2016-09-27 14:22 UTC] hlt99 at blinkenshell dot org
[2016-09-28 07:37 UTC] remi@php.net
-Assigned To:
+Assigned To: mike
[2016-10-04 15:50 UTC] mike@php.net
-Status: Assigned
+Status: Closed
-Type: Security
+Type: Bug
[2016-10-05 06:26 UTC] remi@php.net
-CVE-ID:
+CVE-ID: 2016-7961
[2016-10-05 06:29 UTC] mike@php.net
-Type: Bug
+Type: Security
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Oct 21 21:00:01 2025 UTC |
Description: ------------ The parsing functions of the PECL HTTP extension allow overflowing a buffer with data originating from an arbitrary HTTP request. Affected is the `parse_hostinfo()` function in php_http_url.c that is called when instantiating/initializing an HTTP message object. The problem occurs because in the main processing loop `char *ptr` may get incremented past the corresponding end pointer `char *end` used as the end marker. Thus the parser loop may continue to execute and buffer `state->buffer` may overflow. Relevant code snippet from php_http_url.c:1096: static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr) { [...] if (ptr != end) do { switch (*ptr) { [...] case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* allowed */ if (port) { state->url.port *= 10; state->url.port += *ptr - '0'; } else { label = ptr; state->buffer[state->offset++] = *ptr; } break; [...] default: [...] } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) { if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return FAILURE; } break; } label = ptr; ptr += mb - 1; // ptr increased here as in various other locations } } while (++ptr != end); // ptr pre-incremented + check condition may be missed! [...] # Security impact and PoC Since this bug allows to overwrite quite large parts of memory, arbitrary code execution seems very likely. In [1] you'll find a malformed HTTP request that demonstrates the issue: $ cat http_message_parse.php /* http_message_parse.php 005-bugXXXXX.bin: http://hlt99.blinkenshell.org/php/005-bugXXXXX.bin */ <?php $http_msg = new http\Message(file_get_contents("005-bugXXX.bin"), false); ?> $ ./configure --enable-raphf --enable-propro --with-http && make $ gdb ./sapi/cli/php gdb> r http_message_parse.php [...] Fatal error: Uncaught http\Exception\BadMessageException: http\Message::__construct(): Could not parse HTTP protocol version 'HTTP/1.rdrd-vvv5:##HT [...] // garbled output 85:#~t? HTT in http_message_parse.php on line 7 Program received signal SIGSEGV, Segmentation fault. 0x00000000006d6ef3 in _php_stream_free (stream=<optimized out>, close_options=11) at /home/rc0r/tmp/php-src/main/streams/streams.c:467 467 ret = stream->ops->close(stream, preserve_handle ? 0 : 1); gdb> i r rax 0x4142434445464748 4702394921427289928 rbx 0xb 11 rcx 0x1 1 rdx 0x0 0 rsi 0x1 1 rdi 0x7ffff42ad300 140737289835264 rbp 0x7ffff42ad300 0x7ffff42ad300 rsp 0x7fffffffb150 0x7fffffffb150 r8 0x0 0 r9 0x1 1 r10 0x3d3 979 r11 0x7ffff58ad760 140737312905056 r12 0x0 0 r13 0x1 1 r14 0x0 0 r15 0x0 0 rip 0x6d6ef3 0x6d6ef3 <_php_stream_free+307> eflags 0x10202 [ IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 gdb> x/i $rip => 0x6d6ef3 <_php_stream_free+307>: callq *0x10(%rax) The attempt to parse the supplied HTTP request fails at some point and used resources are freed by the extension. It was possible to overwrite a `php_stream` structure including its pointer to a `php_stream_ops` structure containing function pointers that are about to be called from within `_php_stream_free()` as shown above. Register `rax` contains data from the malformed HTTP request starting at offset 0x2139. [1] http://hlt99.blinkenshell.org/php/005-bugXXXXX.bin # Patch After careful review by the project maintainers the following patch may be used to fix the reported issue. From ec2d2e1648127b2a0bb15f10144daca59bc6f03c Mon Sep 17 00:00:00 2001 From: rc0r <hlt99@blinkenshell.org> Date: Mon, 26 Sep 2016 21:34:29 +0200 Subject: [PATCH] Buffer overflow in parse_hostinfo() fixed --- src/php_http_url.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php_http_url.c b/src/php_http_url.c index 2332fb5..70e4c2c 100644 --- a/src/php_http_url.c +++ b/src/php_http_url.c @@ -1107,7 +1107,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt } #endif - if (ptr != end) do { + if (ptr < end) do { switch (*ptr) { case ':': if (port) { @@ -1235,7 +1235,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt label = ptr; ptr += mb - 1; } - } while (++ptr != end); + } while (++ptr < end); if (!state->url.host) { len = state->offset - len; -- 2.10.0