Hi,
Do you know that Apache HTTP Server and Lighttpd replace non-alnum characters with underscore in name of environment variables?
This might be useful to bypass restrictions of XMLHttpRequest.
Here is a simple CGI script to test server behavior::
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
print "Content-Type: text/plain\n";
for k, v in sorted(os.environ.items()):
print "%s: %s" % (k, v)
And execute this script via Apache::
$ telnet localhost 80
GET /~co3k/envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 10:30:53 GMT
Server: Apache/2.2.20 (Unix) DAV/2 PHP/5.3.6 with Suhosin-Patch
Connection: close
Content-Type: text/plain
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
Then, via Lighttpd::
$ telnet localhost 8037
GET /envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.0 200 OK
Content-Type: text/plain
Connection: close
Date: Wed, 23 Nov 2011 10:43:12 GMT
Server: lighttpd/1.4.28
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
But the case of Nginx::
$ telnet localhost 8080
GET /env/ HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Server: nginx/1.0.9
Date: Wed, 23 Nov 2011 10:57:07 GMT
Content-Type: text/plain
Connection: close
HTTP_X_NORMAL: Hello
Well, as you know, some XMLHttpRequest implementations deny sending some request headers via XMLHttpRequest.
(See also: http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
You can't send Accept-Charset, Accept-Encoding, User-Agent, and etc via Firefox's XMLHttpRequest, but you can send Accept_Charset, Accept.Encoding, UserAgent and etc. CGI script may trust UserAgent header value via "HTTP_USER_AGENT" environment variable.
I've found a vulnerability in the Japanese mobile phone by using this technique. But that vulnerability is caused by unusual custom of Japanese mobile world.
So I want to know more universal threats by using this technique. Do you have some ideas?
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
Nice. Would it make sense if I say the success of this might solely depend
on the order of the spoofed header? or that is obvious?
Different browsers have different order in which the request headers are
stacked. FF 8.0.1 added the actual system User-Agent header before the
custom request headers (User%Agent - created by XMLHttpRequest object).
Chrome and IE 7 both added the custom header before the actual header.
I did not see any ordering preferences in the RFCs.
[ ~ Prasad | @prasadshenoy ~]
On Thu, Jan 5, 2012 at 7:13 AM, Kousuke Ebihara kousuke@co3k.org wrote:
Hi,
Do you know that Apache HTTP Server and Lighttpd replace non-alnum
characters with underscore in name of environment variables?
This might be useful to bypass restrictions of XMLHttpRequest.
Here is a simple CGI script to test server behavior::
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
print "Content-Type: text/plain\n";
for k, v in sorted(os.environ.items()):
print "%s: %s" % (k, v)
And execute this script via Apache::
$ telnet localhost 80
GET /~co3k/envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 10:30:53 GMT
Server: Apache/2.2.20 (Unix) DAV/2 PHP/5.3.6 with Suhosin-Patch
Connection: close
Content-Type: text/plain
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
Then, via Lighttpd::
$ telnet localhost 8037
GET /envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.0 200 OK
Content-Type: text/plain
Connection: close
Date: Wed, 23 Nov 2011 10:43:12 GMT
Server: lighttpd/1.4.28
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
But the case of Nginx::
$ telnet localhost 8080
GET /env/ HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Server: nginx/1.0.9
Date: Wed, 23 Nov 2011 10:57:07 GMT
Content-Type: text/plain
Connection: close
HTTP_X_NORMAL: Hello
Well, as you know, some XMLHttpRequest implementations deny sending some
request headers via XMLHttpRequest.
(See also:
http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
)
You can't send Accept-Charset, Accept-Encoding, User-Agent, and etc via
Firefox's XMLHttpRequest, but you can send Accept_Charset, Accept.Encoding,
UserAgent and etc. CGI script may trust UserAgent header value via
"HTTP_USER_AGENT" environment variable.
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
So I want to know more universal threats by using this technique. Do you
have some ideas?
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.org
This is an artifact of the mismatch between the character set available for Unix shell environment variables and those legal in RFC 822 headers as used by HTTP. The equivalence between at least - and _ is documented in RFC 3875. http://tools.ietf.org/html/rfc3875#section-4.1.18
'Meta-variables with names beginning with "HTTP_" contain values read
from the client request header fields, if the protocol used is HTTP.
The HTTP header field name is converted to upper case, has all
occurrences of "-" replaced with "" and has "HTTP" prepended to
give the meta-variable name.'
That RFC is from 2004, but documents practices that began in 1993.
So I would expect this bug to be present on all CGI-style applications, and absent in frameworks that provide a better object mapping to HTTP values, e.g. servlets.
Given this is documented and standardized behavior, it seems that the XHR spec should be updated to compare at least "_" and possibly other characters not valid in Unix shell variables, as equivalent to "-" when blacklisting custom headers.
Brad Hill
Sr. MTS, Internet Standards and Governance
PayPal Information Risk Management
cell: 206.245.7844 / skype: hillbrad
email: bhill@paypal-inc.com
-----Original Message-----
From: websecurity-bounces@lists.webappsec.org [mailto:websecurity-
bounces@lists.webappsec.org] On Behalf Of Kousuke Ebihara
Sent: Thursday, January 05, 2012 4:13 AM
To: websecurity@lists.webappsec.org
Subject: [WEB SECURITY] A technique for bypassing request header
restriction of XMLHttpRequest
Hi,
Do you know that Apache HTTP Server and Lighttpd replace non-alnum
characters with underscore in name of environment variables?
This might be useful to bypass restrictions of XMLHttpRequest.
Here is a simple CGI script to test server behavior::
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
print "Content-Type: text/plain\n";
for k, v in sorted(os.environ.items()):
print "%s: %s" % (k, v)
And execute this script via Apache::
$ telnet localhost 80
GET /~co3k/envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 10:30:53 GMT
Server: Apache/2.2.20 (Unix) DAV/2 PHP/5.3.6 with Suhosin-Patch
Connection: close
Content-Type: text/plain
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
Then, via Lighttpd::
$ telnet localhost 8037
GET /envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.0 200 OK
Content-Type: text/plain
Connection: close
Date: Wed, 23 Nov 2011 10:43:12 GMT
Server: lighttpd/1.4.28
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
But the case of Nginx::
$ telnet localhost 8080
GET /env/ HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Server: nginx/1.0.9
Date: Wed, 23 Nov 2011 10:57:07 GMT
Content-Type: text/plain
Connection: close
HTTP_X_NORMAL: Hello
Well, as you know, some XMLHttpRequest implementations deny sending
some request headers via XMLHttpRequest.
(See also: http://code.google.com/p/browsersec/wiki/Part2#Same-
origin_policy_for_XMLHttpRequest)
You can't send Accept-Charset, Accept-Encoding, User-Agent, and etc via
Firefox's XMLHttpRequest, but you can send Accept_Charset,
Accept.Encoding, UserAgent and etc. CGI script may trust UserAgent
header value via "HTTP_USER_AGENT" environment variable.
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
So I want to know more universal threats by using this technique. Do you
have some ideas?
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn
http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.or
g
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
What were you able to do?
So I want to know more universal threats by using this technique. Do you
have some ideas?
A couple things come to mind (assuming this works on single word headers which I've been unable to get working)
Modifying headers such as 'Host' to access other virtualhosts on the
same ip, or breaking weak CSRF protections by modifying the 'Referer' header (http://www.securityfocus.com/archive/1/441014)
Potential shared virtual hosting browser cache poisoning?
(http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2008-June/003951.html)
Abusing transparent proxies via Host header modification
(http://www.thesecuritypractice.com/the_security_practice/2010/03/abusing-transparent-proxies-with-flash-presentation-available-paper-update.html)
Regards,
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.org
Actually scratch my last reply.
/me will drink some coffee before hitting the send button next time :)
On Thu, 5 Jan 2012, Robert A. wrote:
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
What were you able to do?
So I want to know more universal threats by using this technique. Do you
have some ideas?
A couple things come to mind (assuming this works on single word headers
which I've been unable to get working)
Modifying headers such as 'Host' to access other virtualhosts on the same
ip, or breaking weak CSRF protections by modifying the 'Referer' header
(http://www.securityfocus.com/archive/1/441014)
Potential shared virtual hosting browser cache poisoning?
(http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2008-June/003951.html)
Abusing transparent proxies via Host header modification
(http://www.thesecuritypractice.com/the_security_practice/2010/03/abusing-transparent-proxies-with-flash-presentation-available-paper-update.html)
Regards,
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.org
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.org
Perhaps it could be combined with the 307 flash header-forging
vulnerability (
http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html
) to forge user-agent headers cross domain; some sites use user-agents
as a weak CSRF protection (don't ask). Or another similar but unpatched
vulnerability.
albino
On Thu, Jan 5, 2012, at 09:13 PM, Kousuke Ebihara wrote:
Hi,
Do you know that Apache HTTP Server and Lighttpd replace non-alnum
characters with underscore in name of environment variables?
This might be useful to bypass restrictions of XMLHttpRequest.
Here is a simple CGI script to test server behavior::
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
print "Content-Type: text/plain\n";
for k, v in sorted(os.environ.items()):
print "%s: %s" % (k, v)
And execute this script via Apache::
$ telnet localhost 80
GET /~co3k/envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 10:30:53 GMT
Server: Apache/2.2.20 (Unix) DAV/2 PHP/5.3.6 with Suhosin-Patch
Connection: close
Content-Type: text/plain
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
Then, via Lighttpd::
$ telnet localhost 8037
GET /envs.cgi.py HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.0 200 OK
Content-Type: text/plain
Connection: close
Date: Wed, 23 Nov 2011 10:43:12 GMT
Server: lighttpd/1.4.28
HTTP_X_DOT: Hello
HTTP_X_NORMAL: Hello
HTTP_X_UNDER: Hello
But the case of Nginx::
$ telnet localhost 8080
GET /env/ HTTP/1.0
X-Normal: Hello
X_Under: Hello
X.Dot: Hello
HTTP/1.1 200 OK
Server: nginx/1.0.9
Date: Wed, 23 Nov 2011 10:57:07 GMT
Content-Type: text/plain
Connection: close
HTTP_X_NORMAL: Hello
Well, as you know, some XMLHttpRequest implementations deny sending some
request headers via XMLHttpRequest.
(See also:
http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
You can't send Accept-Charset, Accept-Encoding, User-Agent, and etc via
Firefox's XMLHttpRequest, but you can send Accept_Charset,
Accept.Encoding, UserAgent and etc. CGI script may trust UserAgent
header value via "HTTP_USER_AGENT" environment variable.
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
So I want to know more universal threats by using this technique. Do you
have some ideas?
Thanks,
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
The Web Security Mailing List
WebSecurity RSS Feed
http://www.webappsec.org/rss/websecurity.rss
Join WASC on LinkedIn http://www.linkedin.com/e/gis/83336/4B20E4374DBA
WASC on Twitter
http://twitter.com/wascupdates
websecurity@lists.webappsec.org
http://lists.webappsec.org/mailman/listinfo/websecurity_lists.webappsec.org
I've found a vulnerability in the Japanese mobile phone by using this
technique. But that vulnerability is caused by unusual custom of Japanese
mobile world.
What were you able to do?
Bypass authentication.
Many sites for Japanese feature phone implements weak authentication system which depends on user identifiers in HTTP header (e.g. X-Up-Subno).
The carrier takes measures to prevent spoofing the identifier.
One of them is a restricted XHR in its web browser. The XHR implementation denies sending "X-Up-Subno" and "X_Up_Subno" request header, but it allows "X.Up.Subno" header, so attacker could spoof the user identifier by using this technique.
Of course, authentication by only ID is too bad. However, in Japanese mobile sites, this "authenticate" method is popular for some reasons, so that vulnerability could create real threats.
--
Kousuke Ebihara kousuke@co3k.org
http://co3k.org/
This is an artifact of the mismatch between the character set available for Unix shell environment variables and those legal in RFC 822 headers as used by HTTP. The equivalence between at least - and _ is documented in RFC 3875. http://tools.ietf.org/html/rfc3875#section-4.1.18
Actually, at least in Unix, shell environment variables can have just
about any character, except for perhaps '\x00' and '=' (IIRC...
haven't looked at the storage format in a while). For example:
$ env 'FOOBAR=BAZ' /bin/sh -c 'set' | grep FOO
FOOBAR='BAZ'
It's just that most shells restrict the characters you can use to set
these or access them. For all I know, other scripting languages could
have similar restrictions. So naturally when defining CGI, someone
felt the need to impose some sort of restrictions on variable names to
be compatible with existing scripting languages, including shell.
As a security guy, I find "squashing" characters down to a single safe
place-holder is always a bad idea, as we see it play out here with
namespace conficts. A better approach would have been to come up with
an encoding/escaping scheme, or to just reject the names you don't
like up front. But what is done is done.
When I first read Kousuke's email, I thought to myself that browsers
(in the XMLHttpRequest context) or web servers really ought to reject
those headers that contain '.' and '*', since those can't be valid
names. As it turns out they are valid, based on the HTTP/1.1 spec.
Relevant excerpts from RFC2616:
CHAR = <any US-ASCII character (octets 0 - 127)>
...
CTL = <any US-ASCII control character
(octets 0 - 31) and DEL (127)>
...
token = 1*<any CHAR except CTLs or separators>
separators = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
...
message-header = field-name ":" [ field-value ]
field-name = token
...
Somewhat surprisingly, all of the following are permitted in HTTP
header names:
!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~
So I would expect this bug to be present on all CGI-style applications, and absent in frameworks that provide a better object mapping to HTTP values, e.g. servlets.
I think it could vary widely from framework to framework, what is
squashed, permitted, and rejected.
Given this is documented and standardized behavior, it seems that the XHR spec should be updated to compare at least "_" and possibly other characters not valid in Unix shell variables, as equivalent to "-" when blacklisting custom headers.
I think given the clearly defined HTTP RFC, we're really looking at
age-old insecure practices in interpreting headers on the web server.
There's no reason that headers with permitted special characters
shouldn't be accessible through an appropriate API. No good reason to
continue squashing and polluting the namespace.
tim
I think given the clearly defined HTTP RFC, we're really looking at age-old
insecure practices in interpreting headers on the web server.
There's no reason that headers with permitted special characters shouldn't
be accessible through an appropriate API. No good reason to continue
squashing and polluting the namespace.
[Hill, Brad] I would say the opposite. Given a documented, common practice that, however hacky, has been established for nearly 20 years, there is every reason for a new technology (or at least, relatively new) not to introduce vulnerabilities to a huge and established ecosystem.
I'm not saying XHR should actually coerce non-alphanumeric characters down when sending headers - only that the security checks for banned headers should do this for purposes of pre-flight comparison. There is an obligation not to introduce new vulnerabilities into existing systems, and the "cost" to long-term compatibility with HTTP is very small: the blacklist becomes a set of simple regexes instead of string literals.
Brad Hill
Co-chair, WebAppSec WG
[Hill, Brad] I would say the opposite. Given a documented, common practice that, however hacky, has been established for nearly 20 years, there is every reason for a new technology (or at least, relatively new) not to introduce vulnerabilities to a huge and established ecosystem.
I'm not saying XHR should actually coerce non-alphanumeric characters down when sending headers - only that the security checks for banned headers should do this for purposes of pre-flight comparison. There is an obligation not to introduce new vulnerabilities into existing systems, and the "cost" to long-term compatibility with HTTP is very small: the blacklist becomes a set of simple regexes instead of string literals.
Well, you can either side with ancient de facto behavior and poor
choices made in a standard that is little used today (CGI), or you can
side with a very prevalent standard (HTTP).
Let us suppose that all browsers do implement work-arounds for these
de facto behaviors in CGIs, then we still don't address the other
problems created by this name squashing.
Consider an application that uses a front-end load balancer. The
application wishes to restrict access to a particular set of external
IP addresses. Since the load balancer terminates those connections,
the application needs the load balancer to pass on information about
what IP address connected. This is normal done through
X-Forwarded-For or similar headers, added by the load balancer to the
request.
Of course this introduces a potential vulnerability right off, even
without problematic name squashing. An attacker could connect from an
untrusted IP address and add his own X-Forwarded-For header. Ok,
fine, we can address that by configuring the load balancer to strip
the X-Forwarded-For header from the intial request, and then add our
own.
But, if name squashing happens on the application server, then the
load balancer will have to strip "X_Forwarded-For", "X*Forwarded_For",
... ad nauseum.
This is just one specific example of the problem of name squashing.
Modern web frameworks should either reject HTTP header names with
special characters they don't like (nginx apparently does this), or
simply allow through any valid HTTP header names. No squashing is
needed.
How would this harm web apps that actually rely on HTTP headers?
tim