Skip to content

Commit 41d49ab

Browse files
committed
Fix GHSA-hgf5-96fm-v528: http user header check of crlf
1 parent ac1a054 commit 41d49ab

File tree

4 files changed

+192
-1
lines changed

4 files changed

+192
-1
lines changed

ext/standard/http_fopen_wrapper.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static inline void strip_header(char *header_bag, char *lc_header_bag,
108108
static bool check_has_header(const char *headers, const char *header) {
109109
const char *s = headers;
110110
while ((s = strstr(s, header))) {
111-
if (s == headers || *(s-1) == '\n') {
111+
if (s == headers || (*(s-1) == '\n' && *(s-2) == '\r')) {
112112
return 1;
113113
}
114114
s++;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
GHSA-hgf5-96fm-v528: Stream HTTP wrapper header check might omit basic auth header (incorrect inside pos)
3+
--FILE--
4+
<?php
5+
$serverCode = <<<'CODE'
6+
$ctxt = stream_context_create([
7+
"socket" => [
8+
"tcp_nodelay" => true
9+
]
10+
]);
11+
12+
$server = stream_socket_server(
13+
"tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
14+
phpt_notify_server_start($server);
15+
16+
$conn = stream_socket_accept($server);
17+
18+
phpt_notify(message:"server-accepted");
19+
20+
$result = fread($conn, 1024);
21+
$encoded_result = base64_encode($result);
22+
23+
fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
24+
25+
CODE;
26+
27+
$clientCode = <<<'CODE'
28+
$opts = [
29+
"http" => [
30+
"method" => "GET",
31+
"header" => "Cookie: foo=bar\nauthorization:x\r\n"
32+
]
33+
];
34+
$ctx = stream_context_create($opts);
35+
var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
36+
var_dump($http_response_header);
37+
CODE;
38+
39+
include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
40+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
41+
?>
42+
--EXPECTF--
43+
array(7) {
44+
[0]=>
45+
string(14) "GET / HTTP/1.1"
46+
[1]=>
47+
string(33) "Authorization: Basic dXNlcjpwd2Q="
48+
[2]=>
49+
string(21) "Host: 127.0.0.1:%d"
50+
[3]=>
51+
string(17) "Connection: close"
52+
[4]=>
53+
string(31) "Cookie: foo=bar
54+
authorization:x"
55+
[5]=>
56+
string(0) ""
57+
[6]=>
58+
string(0) ""
59+
}
60+
array(2) {
61+
[0]=>
62+
string(15) "HTTP/1.0 200 Ok"
63+
[1]=>
64+
string(38) "Content-Type: text/html; charset=utf-8"
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct start pos)
3+
--FILE--
4+
<?php
5+
$serverCode = <<<'CODE'
6+
$ctxt = stream_context_create([
7+
"socket" => [
8+
"tcp_nodelay" => true
9+
]
10+
]);
11+
12+
$server = stream_socket_server(
13+
"tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
14+
phpt_notify_server_start($server);
15+
16+
$conn = stream_socket_accept($server);
17+
18+
phpt_notify(message:"server-accepted");
19+
20+
$result = fread($conn, 1024);
21+
$encoded_result = base64_encode($result);
22+
23+
fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
24+
25+
CODE;
26+
27+
$clientCode = <<<'CODE'
28+
$opts = [
29+
"http" => [
30+
"method" => "GET",
31+
"header" => "Authorization: Bearer x\r\n"
32+
]
33+
];
34+
$ctx = stream_context_create($opts);
35+
var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
36+
var_dump($http_response_header);
37+
CODE;
38+
39+
include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
40+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
41+
?>
42+
--EXPECTF--
43+
array(6) {
44+
[0]=>
45+
string(14) "GET / HTTP/1.1"
46+
[1]=>
47+
string(21) "Host: 127.0.0.1:%d"
48+
[2]=>
49+
string(17) "Connection: close"
50+
[3]=>
51+
string(23) "Authorization: Bearer x"
52+
[4]=>
53+
string(0) ""
54+
[5]=>
55+
string(0) ""
56+
}
57+
array(2) {
58+
[0]=>
59+
string(15) "HTTP/1.0 200 Ok"
60+
[1]=>
61+
string(38) "Content-Type: text/html; charset=utf-8"
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--TEST--
2+
GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct middle pos)
3+
--FILE--
4+
<?php
5+
$serverCode = <<<'CODE'
6+
$ctxt = stream_context_create([
7+
"socket" => [
8+
"tcp_nodelay" => true
9+
]
10+
]);
11+
12+
$server = stream_socket_server(
13+
"tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
14+
phpt_notify_server_start($server);
15+
16+
$conn = stream_socket_accept($server);
17+
18+
phpt_notify(message:"server-accepted");
19+
20+
$result = fread($conn, 1024);
21+
$encoded_result = base64_encode($result);
22+
23+
fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
24+
25+
CODE;
26+
27+
$clientCode = <<<'CODE'
28+
$opts = [
29+
"http" => [
30+
"method" => "GET",
31+
"header" => "Cookie: x=y\r\nAuthorization: Bearer x\r\n"
32+
]
33+
];
34+
$ctx = stream_context_create($opts);
35+
var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
36+
var_dump($http_response_header);
37+
CODE;
38+
39+
include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
40+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
41+
?>
42+
--EXPECTF--
43+
array(7) {
44+
[0]=>
45+
string(14) "GET / HTTP/1.1"
46+
[1]=>
47+
string(21) "Host: 127.0.0.1:%d"
48+
[2]=>
49+
string(17) "Connection: close"
50+
[3]=>
51+
string(11) "Cookie: x=y"
52+
[4]=>
53+
string(23) "Authorization: Bearer x"
54+
[5]=>
55+
string(0) ""
56+
[6]=>
57+
string(0) ""
58+
}
59+
array(2) {
60+
[0]=>
61+
string(15) "HTTP/1.0 200 Ok"
62+
[1]=>
63+
string(38) "Content-Type: text/html; charset=utf-8"
64+
}

0 commit comments

Comments
 (0)