On 18 July 2016, a vulnerability named ‘HTTPoxy’ was announced, affecting some server‑side web applications that run in CGI or CGI‑like environments, such as some FastCGI configurations. Languages known to be affected so far include PHP, Python, and Go.
A number of CVEs have been assigned, covering specific languages and CGI implementations:
- Apache HTTP Server (CVE-2016-5387)
- Apache Tomcat (CVE-2016-5388)
- Go (CVE-2016-5386)
- PHP (CVE-2016-5385)
There is a new website describing the vulnerability, a CERT vulnerability note, and a description of the discovery of the vulnerability. There is additional information on the personal website of Dominic Scheirlinck, an open source web developer at Vend.
This post describes the vulnerability and explains how to use NGINX or NGINX Plus to defeat attempts to exploit it on your servers.
The vulnerability exists because of a namespace clash. A CGI or FastCGI‑like interface sets environment variables based on HTTP request parameters, and these can override internal variables that are used to configure the application.
Currently, the only known exploit of this vulnerability is to web applications running in CGI and CGI‑like environments that use certain HTTP client libraries to make HTTP requests to other services. In this case, attackers can potentially redirect internal requests generated by the application to a server of their choosing, and thus capture any secret data contained in the requests, as shown below.
You can use NGINX or NGINX Plus to identify and defeat attempts to exploit this vulnerability. Doing so provides an effective way to prevent any attacks, giving you time to audit and update any affected code.
How the HTTPoxy Vulnerability is Exploited
Understanding how this vulnerability works – and how to protect your site against it – requires an understanding of how CGI and CGI‑like interfaces set environment variables and how some application libraries are configured by environment variables.
1 – CGI and CGI‑Like Interfaces Define Environment Variables Named HTTP_*
Many web application platforms use CGI or CGI‑like interfaces to connect applications to a web server. These interfaces convert the headers in an HTTP request into environment variables prefixed with HTTP_
. An application can then look up the value of request headers (such as the User-Agent
) by inspecting its environment.
A client can create arbitrary environment variables (beginning with HTTP_
) in the application’s environment by sending requests with the appropriate header. For instance, the request header Foo:
bar
becomes the environment variable HTTP_FOO=bar
.
Some platforms provide an abstraction layer that conceals the environment variables, such as PHP’s $_SERVER
global variable. Nevertheless, these abstractions are built on top of the standard CGI and FastCGI practice of setting environment variables.
For example, when running in FastCGI mode, a PHP application can determine the User-Agent
header of a request as follows:
// both methods return the same result
$useragent = getenv( 'HTTP_USER_AGENT' );
$useragent = $_SERVER['HTTP_USER_AGENT'];
2 – Some Application Libraries Are Configured from Environment Variables
A complex web application pulls in functionality from external libraries. For example, sometimes applications need to make HTTP requests to other services (in a microservices‑like fashion) and they may use one of the common third‑party libraries to do so. These libraries often support a feature called an HTTP Proxy, which is an intermediary server used to relay the HTTP request.
One easy way to configure a library like this is to define the configuration through environment variables. The widely used PHP Guzzle library is configured in part by an environment variable named HTTP_PROXY
, which is set to the address of a proxy server. If HTTP_PROXY
is set in this way, the library then relays all the HTTP requests that it generates to the proxy server’s address. Go’s net/http
package and Python’s Requests module also trust and interpret the HTTP_PROXY
environment variable in the same way.
3 – The Nature of the Vulnerability
The libraries described in item 2 were not designed with CGI or CGI‑like interfaces in mind, and the HTTP_PROXY
environment variable that they trust overlaps with the HTTP_
namespace used by CGI and FastCGI interfaces as discussed in item 1.
By setting the value of the HTTP_PROXY
environment variable to an address of their own choosing, attackers can redirect and capture internal HTTP requests generated by the application. These requests may contain sensitive information, such as authentication keys and private data, and they may reveal information about additional APIs and endpoints that can be exploited.
An attacker can do this by sending a request with a Proxy
header, and the CGI or FastCGI interface obediently creates an environment variable named HTTP_PROXY
for that invocation of the application. Note that only requests that contain the bogus Proxy
header are directly affected.
Defeating the Attack using NGINX and NGINX Plus
The HTTPoxy vulnerability does not directly affect NGINX, but NGINX and NGINX Plus can be used to stop attacks based on this vulnerability.
Talking to an Upstream FastCGI Application
You can use NGINX to “sanitize” the input to the application by setting the HTTP_PROXY
FastCGI parameter to the empty string. This removes the parameter completely from the FastCGI request:
fastcgi_param HTTP_PROXY "";
Load Balancing and Proxying HTTP Traffic
When proxying HTTP requests to an upstream application, it’s wise to set any Proxy
header to the empty string, in case the upstream application is running on a vulnerable platform:
proxy_set_header Proxy "";
Detecting Attempts to Exploit the Vulnerability
Proxy
is not a standard HTTP header, so any requests that contain this header can be regarded as suspicious. You can use NGINX or NGINX Plus to log these suspicious requests to a dedicated access log, here named badactor.log:
# define 'proxylog' format in the http{} context:
log_format proxylog '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_proxy"';
# log requests with a Proxy header using the 'proxylog' format
access_log /var/log/nginx/badactor.log proxylog if=$http_proxy;
Note: In the configuration context where you place this access_log
directive, it overrides any access logging defined at a higher level in the NGINX configuration.
Stay Safe
NGINX and NGINX Plus provide an effective way to monitor and defeat the HTTPoxy attack. Use the techniques described above to protect your application while you audit, update, and test your code to remove the vulnerability.
If you have any questions, please comment on this post – or, if you are an NGINX Plus subscriber, don’t hesitate to contact our support team for assistance.