Skip to content

Commit ce2abdd

Browse files
committed
Merge branch 'PHP-7.4'
* PHP-7.4: Fixes #79265: Improper injection of Host header when using fopen for http requests
2 parents 6c7306f + e855b28 commit ce2abdd

File tree

2 files changed

+102
-28
lines changed

2 files changed

+102
-28
lines changed

ext/standard/http_fopen_wrapper.c

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -457,41 +457,76 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
457457
strip_header(user_headers, t, "content-type:");
458458
}
459459

460-
if ((s = strstr(t, "user-agent:")) &&
461-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
462-
*(s-1) == '\t' || *(s-1) == ' ')) {
463-
have_header |= HTTP_HEADER_USER_AGENT;
460+
s = t;
461+
while ((s = strstr(s, "user-agent:"))) {
462+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
463+
*(s-1) == '\t' || *(s-1) == ' ') {
464+
have_header |= HTTP_HEADER_USER_AGENT;
465+
break;
466+
}
467+
s++;
464468
}
465-
if ((s = strstr(t, "host:")) &&
466-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
467-
*(s-1) == '\t' || *(s-1) == ' ')) {
468-
have_header |= HTTP_HEADER_HOST;
469+
470+
s = t;
471+
while ((s = strstr(s, "host:"))) {
472+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
473+
*(s-1) == '\t' || *(s-1) == ' ') {
474+
have_header |= HTTP_HEADER_HOST;
475+
break;
476+
}
477+
s++;
469478
}
470-
if ((s = strstr(t, "from:")) &&
471-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
472-
*(s-1) == '\t' || *(s-1) == ' ')) {
473-
have_header |= HTTP_HEADER_FROM;
479+
480+
s = t;
481+
while ((s = strstr(s, "from:"))) {
482+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
483+
*(s-1) == '\t' || *(s-1) == ' ') {
484+
have_header |= HTTP_HEADER_FROM;
485+
break;
474486
}
475-
if ((s = strstr(t, "authorization:")) &&
476-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
477-
*(s-1) == '\t' || *(s-1) == ' ')) {
478-
have_header |= HTTP_HEADER_AUTH;
487+
s++;
479488
}
480-
if ((s = strstr(t, "content-length:")) &&
481-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
482-
*(s-1) == '\t' || *(s-1) == ' ')) {
483-
have_header |= HTTP_HEADER_CONTENT_LENGTH;
489+
490+
s = t;
491+
while ((s = strstr(s, "authorization:"))) {
492+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
493+
*(s-1) == '\t' || *(s-1) == ' ') {
494+
have_header |= HTTP_HEADER_AUTH;
495+
break;
496+
}
497+
s++;
484498
}
485-
if ((s = strstr(t, "content-type:")) &&
486-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
487-
*(s-1) == '\t' || *(s-1) == ' ')) {
488-
have_header |= HTTP_HEADER_TYPE;
499+
500+
s = t;
501+
while ((s = strstr(s, "content-length:"))) {
502+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
503+
*(s-1) == '\t' || *(s-1) == ' ') {
504+
have_header |= HTTP_HEADER_CONTENT_LENGTH;
505+
break;
506+
}
507+
s++;
489508
}
490-
if ((s = strstr(t, "connection:")) &&
491-
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
492-
*(s-1) == '\t' || *(s-1) == ' ')) {
493-
have_header |= HTTP_HEADER_CONNECTION;
509+
510+
s = t;
511+
while ((s = strstr(s, "content-type:"))) {
512+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
513+
*(s-1) == '\t' || *(s-1) == ' ') {
514+
have_header |= HTTP_HEADER_TYPE;
515+
break;
516+
}
517+
s++;
494518
}
519+
520+
s = t;
521+
while ((s = strstr(s, "connection:"))) {
522+
if (s == t || *(s-1) == '\r' || *(s-1) == '\n' ||
523+
*(s-1) == '\t' || *(s-1) == ' ') {
524+
have_header |= HTTP_HEADER_CONNECTION;
525+
break;
526+
}
527+
s++;
528+
}
529+
495530
/* remove Proxy-Authorization header */
496531
if (use_proxy && use_ssl && (s = strstr(t, "proxy-authorization:")) &&
497532
(s == t || *(s-1) == '\r' || *(s-1) == '\n' ||

ext/standard/tests/http/bug79265.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
Bug #79265 (Improper injection of Host header when using fopen for http requests)
3+
--INI--
4+
allow_url_fopen=1
5+
--SKIPIF--
6+
<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
7+
--FILE--
8+
<?php
9+
require 'server.inc';
10+
11+
$responses = array(
12+
"data://text/plain,HTTP/1.0 200 OK\r\n\r\n",
13+
);
14+
15+
$pid = http_server("tcp://127.0.0.1:12342", $responses, $output);
16+
17+
$opts = array(
18+
'http'=>array(
19+
'method'=>"GET",
20+
'header'=>"RandomHeader: localhost:8080\r\n" .
21+
"Cookie: foo=bar\r\n" .
22+
"Host: userspecifiedvalue\r\n"
23+
)
24+
);
25+
$context = stream_context_create($opts);
26+
$fd = fopen('http://127.0.0.1:12342/', 'rb', false, $context);
27+
fseek($output, 0, SEEK_SET);
28+
echo stream_get_contents($output);
29+
fclose($fd);
30+
31+
http_server_kill($pid);
32+
33+
?>
34+
--EXPECT--
35+
GET / HTTP/1.0
36+
Connection: close
37+
RandomHeader: localhost:8080
38+
Cookie: foo=bar
39+
Host: userspecifiedvalue

0 commit comments

Comments
 (0)