HTTP Response Splitting

This blog post describes about the lesser known attack, targeted towards HTTP Headers due to improper input validation. It also describes on how other attacks can be mounted using this mechanism.


All the websites rely upon HTTP to transmit data between client(browser) and server. Client sends a request by typing in the URL and server sends a response to that request, and a webpage is displayed. HTTP headers are the core part of these requests and responses. They usually carry information regarding the browser, the requested page, cookies etc. The header’s look like this :


I wouldn’t get in detail about each header field, but one thing to remember for this article is the response codes. Usually, when the response is successful we get 200 OK as response code, 404 NOT FOUND if the resource is unavailable, most importantly for our discussion we focus on 302 Moved Temporarily response code. Let’s look at the headers in this case :


The Location header field in 302 Response is of at most important, The browser now sends request back to server based on the contents of Location field. Let’s look why this header field is also important for exploiting this attack.


Consider a server which accepts user input through some form or search or anything which is sent as POST data. The server does not sanitize the user input, allowing the user to enter any arbitrary data. Each line in HTTP header is separated by CR/LF(for windows) and LF(for linux). CR means carriage return and LF means line feed, this is crucial while parsing because it tells the end of line. The attacker cleverly crafts another request inside the input field, for eg., In the headers above given as example have lang=en has User influence, so the attacker can send data as:

  1. The value ‘USA’.

  2. CR/LF - %0d%0a

  3. A response with Content Length 0 [we don’t bother about this response.]

  4. CR/LF - %0d%0a

  5. A response which contains malicious content [For e.g. Javascript which will download malware when the page is visited]


Let’s analyze what we have sent in the lang input field. The first line shows our original request for en, but the attacker does not stop here, he continues to add more lines, the second line is the response where we set the Content-Length as zero, since we don’t have anything here. The next response is separated by delimiter CR/LF, and our second response is crafted. This is valid as per HTTP protocol and will be processed. Let’s summarize once, the attacker can control the input parameter, he sends the first request along with two responses, the first response is linked to first request, but there is still the second response which hangs in there since there is no second request. Hence, the attacker immediately sends in a second request, lets say to a login page:


Now, this second request is linked to the second response which is still hanging there, since this is how the protocol works. So, despite he requests for login.php in the second request, he gets the second response which says “you have been phished”. But, how is this useful to an attacker, whatever happened till now would work only for attacker. How is going to send the malicious page to other users. Read onto to the next section, on how is this useful and how various other attacks can be mounted.


In the previous section, we said that the malicious response goes back to attacker, and he needs to send this page to other users. This is where the necessity of a proxy server or some machine which sits in between and caches requests and responses comes in. The attacker needs to behind a proxy server which then passes his requests to the original server, as well other users also need to be behind the same proxy. Let’s retrace the steps what we done above :

  1. Attacker sends a request and two responses, using the delimiter %0d%0a.

  2. The request is sent to the server, but now the request passes through a caching proxy. The caching proxy links the first request to first response, but the second response hangs very briefly as there is no matching request.

  3. Attacker immediately sends a second request(login.php), which is again sent through the proxy.

  4. The moment the proxy sees the request for login.php, it links to the second response which is hanging there, thus displaying the malicious page.


Note: This is why re-direction helps, it itself sends a second request and thereby matches to the second malicious response. From now on any request to login.php by any user behind that proxy, will get the malicious page. This is because of how caching works, it caches the response for requests often made. This malicious response stays until the cache expires. With this mechanism, it is possible to mount various kinds of attacks : Web Cache Poisoning (defacement)

> > Till now whatever we have discussed is a classic example of cache poisoning, but the attacker can do an even better cache poisoning. In the response header, there is an another field called Last-Modified, this is precisely the information for how long the cache should be retained. If the date in the Last-Modified field is less than the current date, then the cache is removed from the proxy and a fresh copy is cached, in order to avoid this, the attacker can set the Last-Modified date to a future date, that is not very near. For eg., [![1](/images/2013/03/15.png)](/images/2013/03/15.png) > >

Cross-Site Scripting (XSS)

> > Until now, it has been impossible to mount XSS attacks on sites through a redirection script when the clients use IE unless the Location header can be fully controlled. With HTTP Response Splitting, it is possible to mount a XSS attack even if the Location header is only partially controlled by the attacker. > >

Cross User attacks (single user, single page, temporary defacement)

> > As a variant of the attack, it is possible for the attacker not to send the second request. This seems odd at first, but the idea is that in some cases, the target may share the same TCP connection with the server, among several users (this is the case with some cache servers). The next user to send a request to the web server through the target will be served by the target with the second response the attacker generated. The net result is having a client of the web site being served with a resource that was crafted by the attacker. This enables the attacker to “deface” the site for a single page requested by a single user (a local, temporary defacement). Much like the previous item, in addition to defacement, the attacker can steal session cookies and/or set them. > >

Browser cache poisoning

> > This is a special case of “Web Cache Poisoning”. It is somewhat similar to XSS in the sense that in both the attacker needs to target individual clients. However, unlike XSS, it has a long lasting effect because the spoofed resource remains in the browser’s cache. > >


In order for the attack to work you must encode the input, this can be done by visiting this website, where you can provide your maliciously crafted input and when we select the encodeURIComponent, you will get your encoded string, the above input looks like this :


Note: Web-server running in linux would only require %0A(LF), whereas in windows %0D%0A(CRLF) is required.

Web Cache Poisoning

Remember for web cache poisoning, all we need to do is add an extra field which sets the cache expiry to very far date from the current date


Cross-Site Scripting

In cross-site scripting, attacker needs to write some javascript to steal cookie, or etc. since the whole response body is controlled by attacker, he can easily insert scripting. The exploit would look something like this:

en%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2029%0d%0a%0d%0a%3Cscript%3Ealert("XSS") %3C%2Fscript%3E


Like any other attack, this is data passed in by the user, or which is under influence. Sanitizing the input fields is very important. Any time you set header information inside your application, make sure that the data either cannot be modified by a user,or it is well sanitized. Also, you could check for the length of data that is being passed.