Skip to content

Commit da023a8

Browse files
bukkaremicollet
authored andcommitted
Fix GHSA-c5f2-jwm7-mmq2: stream HTTP fulluri CRLF injection
(cherry picked from commit 426a6d4539ebee34879ac5de857036bb6ff0e732) (cherry picked from commit bc1f192) (cherry picked from commit 8d130e1) (cherry picked from commit 494de65) (cherry picked from commit dcb89ed) (cherry picked from commit 1178705) (cherry picked from commit 59bfc16) (cherry picked from commit 8dab7d0)
1 parent 355cd5c commit da023a8

File tree

2 files changed

+45
-12
lines changed

2 files changed

+45
-12
lines changed

ext/standard/http_fopen_wrapper.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
178178
return NULL;
179179
}
180180

181+
/* Should we send the entire path in the request line, default to no. */
182+
if (context && php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) {
183+
zval ztmp = **tmpzval;
184+
185+
zval_copy_ctor(&ztmp);
186+
convert_to_boolean(&ztmp);
187+
request_fulluri = Z_BVAL(ztmp) ? 1 : 0;
188+
zval_dtor(&ztmp);
189+
}
190+
181191
use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';
182192
/* choose default ports */
183193
if (use_ssl && resource->port == 0)
@@ -197,6 +207,13 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
197207
}
198208
}
199209

210+
if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) {
211+
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper full URI path does not allow CR or LF characters");
212+
php_url_free(resource);
213+
efree(transport_string);
214+
return NULL;
215+
}
216+
200217
if (context && php_stream_context_get_option(context, wrapper->wops->label, "timeout", &tmpzval) == SUCCESS) {
201218
SEPARATE_ZVAL(tmpzval);
202219
convert_to_double_ex(tmpzval);
@@ -382,18 +399,6 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
382399
strncpy(scratch, "GET ", scratch_len);
383400
}
384401

385-
/* Should we send the entire path in the request line, default to no. */
386-
if (!request_fulluri &&
387-
context &&
388-
php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) {
389-
zval ztmp = **tmpzval;
390-
391-
zval_copy_ctor(&ztmp);
392-
convert_to_boolean(&ztmp);
393-
request_fulluri = Z_BVAL(ztmp) ? 1 : 0;
394-
zval_dtor(&ztmp);
395-
}
396-
397402
if (request_fulluri) {
398403
/* Ask for everything */
399404
strcat(scratch, path);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GHSA-c5f2-jwm7-mmq2 (Configuring a proxy in a stream context might allow for CRLF injection in URIs)
3+
--INI--
4+
allow_url_fopen=1
5+
--CONFLICTS--
6+
server
7+
--FILE--
8+
<?php
9+
$serverCode = <<<'CODE'
10+
echo $_SERVER['REQUEST_URI'];
11+
CODE;
12+
13+
include __DIR__."/../../../../sapi/cli/tests/php_cli_server.inc";
14+
php_cli_server_start($serverCode, null);
15+
16+
$host = PHP_CLI_SERVER_ADDRESS;
17+
$userinput = "index.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index2.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index.php";
18+
$context = stream_context_create(['http' => ['proxy' => 'tcp://' . $host, 'request_fulluri' => true]]);
19+
echo file_get_contents("http://$host/$userinput", false, $context);
20+
?>
21+
--EXPECTF--
22+
Warning: file_get_contents(http://localhost:%d/index.php HTTP/1.1
23+
Host: localhost:%d
24+
25+
GET /index2.php HTTP/1.1
26+
Host: localhost:%d
27+
28+
GET /index.php): failed to open stream: HTTP wrapper full URI path does not allow CR or LF characters in %s on line %d

0 commit comments

Comments
 (0)