diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 7b18e17f0d8f..51e2b3f0bb20 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -264,6 +264,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* if the user has configured who they are, send that as the password */ if (FG(from_address)) { + PHP_FTP_CNTRL_CHK(FG(from_address), strlen(FG(from_address)), "Invalid password %s") php_stream_printf(stream, "PASS %s\r\n", FG(from_address)); } else { php_stream_write_string(stream, "PASS anonymous\r\n"); diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 89125ed0765e..ee8e874c79d1 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -82,6 +82,20 @@ #define HTTP_WRAPPER_REDIRECTED 2 #define HTTP_WRAPPER_KEEP_METHOD 4 +static bool php_http_valid_from_address(const char *from) +{ + const unsigned char *s = (const unsigned char *) from; + + while (*s) { + if (iscntrl(*s)) { + return false; + } + s++; + } + + return true; +} + static inline void strip_header(char *header_bag, char *lc_header_bag, const char *lc_header_name) { @@ -783,9 +797,13 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* if the user has configured who they are, send a From: line */ if (!(have_header & HTTP_HEADER_FROM) && FG(from_address)) { - smart_str_appends(&req_buf, "From: "); - smart_str_appends(&req_buf, FG(from_address)); - smart_str_appends(&req_buf, "\r\n"); + if (php_http_valid_from_address(FG(from_address))) { + smart_str_appends(&req_buf, "From: "); + smart_str_appends(&req_buf, FG(from_address)); + smart_str_appends(&req_buf, "\r\n"); + } else { + php_error_docref(NULL, E_WARNING, "Cannot construct From header"); + } } /* Send Host: header so name-based virtual hosts work */ diff --git a/ext/standard/tests/http/from_address_cntrl.phpt b/ext/standard/tests/http/from_address_cntrl.phpt new file mode 100644 index 000000000000..0adbf1293391 --- /dev/null +++ b/ext/standard/tests/http/from_address_cntrl.phpt @@ -0,0 +1,36 @@ +--TEST-- +http wrapper must not build a From header from a from address with control characters +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + $pid, 'uri' => $uri] = http_server($responses, $output); + +ini_set('from', "evil@example.com\r\nX-Injected: yes"); +file_get_contents($uri); + +ini_set('from', 'me@example.com'); +file_get_contents($uri); + +http_server_kill($pid); + +rewind($output); +$sent = stream_get_contents($output); +var_dump(str_contains($sent, 'X-Injected')); +var_dump(str_contains($sent, 'From: me@example.com')); +?> +--EXPECTF-- +Warning: file_get_contents(): Cannot construct From header in %s on line %d +bool(false) +bool(true) diff --git a/ext/standard/tests/network/ftp_from_pass_cntrl.phpt b/ext/standard/tests/network/ftp_from_pass_cntrl.phpt new file mode 100644 index 000000000000..9543d1e15876 --- /dev/null +++ b/ext/standard/tests/network/ftp_from_pass_cntrl.phpt @@ -0,0 +1,55 @@ +--TEST-- +FTP anonymous PASS from the from address must reject control characters +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false)