Subject: [NEW ISSUE] Content-Length and Transfer-Encoding: security implications

From: Yutaka OIWA <[email-masked]>
Date: Wed, 05 Dec 2007 03:15:14 +0900

Dear ietf-http-wg members,

This is to reopen the issue submitted on 22 NOV 2007 by Bjoern Hoehrmann
(http://lists.w3.org/Archives/Public/ietf-http-wg/2007OctDec/0264.html),
on this time as a security issue.

In Section 4.4 of <draft-lafon-rfc2616bis-latest> (as of 03 DEC 2007), 
there is a description as follows:

> Messages MUST NOT include both a Content-Length header field and a 
> transfer-coding. If the message does include a transfer-coding, the 
> Content-Length MUST be ignored.

However, this specification makes interoperability security problem with 
HTTP/1.0 clients/servers.

The original post by Bjoern noted this as a general problem, but this 
has been one of the reason which caused Mozilla security issue #297078 
(https://bugzilla.mozilla.org/show_bug.cgi?id=297078), reported in July 
2005 by me.  This causes "request splitting" vulnerability.

Imagine that there is the following request stream:

  POST /a HTTP/1.0
  Host: hostname.domain.name.jp
  User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.8) Gecko/20050513
  bian/1.7.8-1
  Keep-Alive: 300
  Connection: keep-alive
  Transfer-Encoding: chunked
  Content-Type: text/xml
  Content-Length: 113
  
  0
  
  POST /~yutaka/cgi-bin/test2.cgi?exploit=yes HTTP/1.0
  Host: hostname.domain.name.jp
  Content-Length: 500

The client sent only one valid request to the server: in HTTP/1.0, 
"Transfer-Encoding" header is an extension entity header and is allowed. 
However, if an HTTP/1.1 server examines this, it will be interpreted as 
TWO requests: now Transfer-Encoding is a defined entity header, and due 
to the rule the server MUST parse it as two requests.

The same problem will occur with responses, too. For example, an 
HTTP/1.0 server with CGI capability can make valid HTTP/1.1 clients 
misunderstand the response boundary.  In this case, if there is either 
virtual hosting or a proxy,  the attacker host can inject any data 
including scripts to contents of another host, which is called 
"cross-site content injection vulnerability".  The attacked site cannot
prevent this to happen by their own means.

In current phrasing of the RFC2616, it is generally understood as: if 
both headers are present, the requested behavior is to accept the 
message by discarding Content-Length header. Many servers/clients seems 
to be implemented in this way, but it is a very bad practice. I think 
that the clause in Section 4.4 should be updated to something like 
either of the following:

(case 1: my recommendation is the stronger requirement)
> Messages MUST NOT include both a Content-Length header field and a 
> transfer-coding. If a request does include both, the server MUST 
> return 400 (Bad Request) and close the connection.
> If a response includes both, the client MUST ignore any data sent and
> close the connection immediately.

or (case 2: if it is inappropriate to add any new MUST-type restriction 
in rfc2616bis)

> Messages MUST NOT include both a Content-Length header field and a 
> transfer-coding. If the message does include a transfer-coding, the 
> Content-Length MUST be ignored.  The server SHOULD return 400 (Bad 
> Request) for such requests.  The client SHOULD NOT accept any responses 
> following such an invalid response in a keep-alive connection, and MAY 
> reject such a response.

A similar description in the item 3. in the same section should also
be updated.

-- 
Yutaka OIWA, Ph.D.                                       Research Scientist
                            Research Center for Information Security (RCIS)
    National Institute of Advanced Industrial Science and Technology (AIST)
                      Mail addresses: <[email-masked]>, <[email-masked]>
OpenPGP: id[995DD3E1] fp[3C21 17D0 D953 77D3 02D7 4FEC 4754 40C1 995D D3E1]

---

From: Adrien de Croy <[email-masked]>
Date: Wed, 05 Dec 2007 07:55:40 +1300

>   Host: hostname.domain.name.jp
If a request like this were to be sent through an HTTP/1.1 capable proxy
which behaves according to the recommendations of the spec, the proxy
would likely turn this into an HTTP/1.1 request upstream.  e.g. the case
where one sends

  POST http://hostname.domain.name.jp/a HTTP/1.0
  Host: hostname.domain.name.jp
  User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.8) 
Gecko/20050513
  bian/1.7.8-1
  Keep-Alive: 300
  Connection: keep-alive
  Transfer-Encoding: chunked
  Content-Type: text/xml
  Content-Length: 113

  0

  POST /~yutaka/cgi-bin/test2.cgi?exploit=yes HTTP/1.1
  Host: hostname.domain.name.jp
  Content-Length: 500

to a proxy, would cause most proxies (unless they explicitly check for
this) to send 2 POST requests to that server.

Does this mean there should (if there are no further recommendations
made for servers / UAs) at least be some requirements specified for
proxies in this case?

e.g a proxy must not change the meaning of request headers (in this case
Transfer-encoding) by virtue of simply forwarding the request with a
different HTTP version tag.

Regards

Adrien

-- 
Adrien de Croy - WinGate Proxy Server - http://www.wingate.com

---

From: Adrien de Croy <[email-masked]>
Date: Wed, 05 Dec 2007 09:08:01 +1300

Yutaka Oiwa wrote:
> Adrien de Croy wrote:
> Yes.  The proxy should not forward at least second request to the upstream.
>   
the problem is, to the proxy this second request is simply entity body.  
To the receiving server however it's a pipelined request.

Wouldn't the best approach be to ban Transfer-Encoding from HTTP/1.0 
clients?  Removing the Transfer-Encoding header in this case solves the 
problem, as then the payload of the post is correctly encapsulated.

So maybe the requirement needs to be dependent on the HTTP version 
number.  i.e.

for HTTP/1.0 requests, Content-length takes precedence, and 
Transfer-Encoding should be ignored and removed by proxies
for HTTP/1.1 requests, Transfer-Encoding takes precedence, and 
Content-Length should be ignored and removed by proxies.

> Maybe yes.  However, such "indirect" specification requires every proxy to
> understand the meaning of request in older versions of protocol, and carefully
> implement the comparison of "the meaning".  Another issue is some kind of
> "forward compatibility" nature of the HTTP: such specification forbid HTTP/1.1
> proxies to understand defacto-standard HTTP/1.0 Host and Connection headers.
> Instead, I prefer to explicitly forbid Content-Length/Transfer-Encoding case.
>
>

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 06 Dec 2007 04:10:15 +0100

> problem, as then the payload of the post is correctly encapsulated.

Yes, a SHOULD requirement that servers and clients SHOULD reject
HTTP/1.0 messages using chunked transfer-encoding as invalid would be a
good thing. Required to solve interoperability issues regarding these
requests when there is an HTTP/1.0 proxy in the path.

For a pure HTTP/1.1 path (or any path where there isn't an HTTP/1.0
proxy) the existing wording works.

Note: there is some servers out there in the whild who respond with both
Content-Length and chunked.. but probably not many...

http://www.squid-cache.org/mail-archive/squid-users/200711/0605.html

Regards
Henrik