Browse Source

[security] do not emit HTTP_PROXY to CGI env

Strip bogus "Proxy" header before creating subprocess environment.
(mod_cgi, mod_fastcgi, mod_scgi, mod_ssi, mod_proxy)

Do not emit HTTP_PROXY to subprocess environment.
Some executables use HTTP_PROXY to configure outgoing proxy.

This is not a lighttpd security issue per se, but this change to
lighttpd adds a layer of defense to protect backend processes which
might be vulnerable due to blindly using this untrusted environment
variable.  The HTTP_PROXY environment variable should not be trusted
by a program running in a CGI-like environment.

Mitigation in lighttpd <= 1.4.40 is to reject requests w/ Proxy header:

* Create "/path/to/deny-proxy.lua", read-only to lighttpd, with content:
  if (lighty.request["Proxy"] == nil) then return 0 else return 403 end
* Modify lighttpd.conf to load mod_magnet and run lua code
    server.modules += ( "mod_magnet" )
    magnet.attract-raw-url-to = ( "/path/to/deny-proxy.lua" )

References:

https://www.kb.cert.org/vuls/id/797896
CGI web servers assign Proxy header values from client requests to
internal HTTP_PROXY environment variables

https://httpoxy.org/
httpoxy: A CGI application vulnerability
personal/stbuehler/mod-csrf-old
Glenn Strauss 5 years ago
parent
commit
779c133c16
  1. 7
      src/mod_cgi.c
  2. 7
      src/mod_fastcgi.c
  3. 4
      src/mod_proxy.c
  4. 7
      src/mod_scgi.c
  5. 9
      src/mod_ssi.c

7
src/mod_cgi.c

@ -1289,6 +1289,13 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
ds = (data_string *)con->request.headers->data[n];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));

7
src/mod_fastcgi.c

@ -1888,6 +1888,13 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
ds = (data_string *)con->request.headers->data[i];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);

4
src/mod_proxy.c

@ -494,6 +494,10 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Connection"))) continue;
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) continue;
buffer_append_string_buffer(b, ds->key);
buffer_append_string_len(b, CONST_STR_LEN(": "));

7
src/mod_scgi.c

@ -1536,6 +1536,13 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
ds = (data_string *)con->request.headers->data[i];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));

9
src/mod_ssi.c

@ -165,7 +165,14 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* don't forward the Authorization: Header */
if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Authorization"))) {
continue;
}
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}

Loading…
Cancel
Save