Thursday, February 01, 2007

HTTP Response Splitting Attacks Without Proxies

I've had this paper sitting around collecting dust for so long, but I've been keeping it for a reason, me and a friend (troopa) are trying to start a hacker/infosec community focused around Research and Development of ideas and attacks, rather than simply a teaching and learning ground for people, because there are plenty of those already in existence, but very few places where people come together to collaborate on new ideas, and so I present to you Sudo Labs.

I initially posted the full paper on Sudo Labs here: http://sudolabs.com/forum/viewtopic.php?t=3

But now that I've directed a bit of traffic there (that really didn't help), I'm posting it here as well:

[EDIT (14/02/07)]: I've been informed, that my introduction was completely wrong and may have mislead people, and so I've replaced it.

HTTP Response Splitting Attacks Without Proxies


By kuza55
of Sudo labs

Contents:

1.0 Introduction
2.0 The Attack
    2.1 Theory
    2.2 Browser Inconsistencies
    2.3 Working Exploits
3.0 Implementation Notes
4.0 Conclusion

1.0 Introduction

At the moment, the only know technique (AFAIK - Correct me if I'm wrong) for attacking the browser cache to alter the cache for pages other than the one vulnerable to HTTP Response Splitting is the One proposed by Amit Klein on page 19-21 of this paper: http://www.packetstormsecurity.org/papers/general/whitepaper_httpresponse.pdf

It utilises the fact that IE operates on only 4 connections to request pages from a single server.

This paper will illustrate something similar.

2.0 The Attack

As many people before me have discovered; if you can force the browser to make a request for a page on the connection you control, you can replace the contents of the page.

The problem has been to force the browser to do just that.

But what if we ask nicely?

2.1 Theory

If in our doctored response we redirect the user to another page on our site and we send the browser the "Keep-Alive: timeout=300" and "Connection: Keep-Alive" headers the browser does exactly what we asked it and sends the request on that connection (except Opera 9, which doesn't want to - Opera 8 does).

The next thing we need to do is to send the browser a "Content-Length: 0" header so that it thinks its received everything its going to from its first request and sends the second request straight away.

We then send the browser a couple of new lines, and then lots of extraneous spaces and then a new line as well.

This works much like a NOP sled in Buffer Overflow attack, because this way we can prepare a landing zone for the browser which it will just ignore before reading the actual response, this gives us greater flexibility in regards to browser inconsistencies and network latency issues.

2.2 Browser Inconsistencies



Sadly not all the browsers react the same way, and so not everything can be done easily, here's a little chart at what I've been able to produce in various browsers so far:

1 = Second request made on the same connection.
2 = Second Response can be injected into
3 = Headers can be injected into the second response
4 = Content-Length Header is strictly obeyed

+ = yes
~ = Sort of
- = No
x = N/A

-----------------
|Browser|1|2|3|4|
-----------------
|Opera 8|+|+|+|+|
-----------------
|IE 6 |+|+|+|~|
-----------------
|Firefox|+|+|-|x|
-----------------
|Opera 9|-|-|-|x|
-----------------

So essentially I've only really been able to exploit the attack's full potential under IE 6 and Opera 8. So getting this to work under Firefox (and possibly Opera 9) is for people with more experience in how browser work with the network.

The issue with Internet Explorer is that it reads things in 1024 byte blocks, and so any Content-Length headers which to not fall on that boundary will be rounded up to the nearest kilobyte, but that's not much of an issue.

Internet Explorer also has a 2047 byte limitation on query strings, so my original design of using new lines doesn't work because they get encoded in the query string to 3 times their length (6 bytes - %0d%0a - instead of two), and so spaces had to be used as the white spaces to be ignored.

For some reason I can't seem to get Firefox to use the headers I provide, but you can easily inject into the top of the page, and simply make the browser not render the rest by using an unclosed div tag with a display: none style attribute.

Opera 9 (as I mentioned earlier) though, just doesn't want to make the request on the same socket, and so I haven't been able to get this attack to work.

2.3 Working Exploits



Now, onto the interesting part - Working Exploits.

This *works* (To the extent explained above) in both IE and Firefox:

http://www.dataplace.org/redir.html?url=index.html%0d%0aKeep-Alive: timeout=60%0d%0aConnection: Keep-Alive%0d%0aContent-Type: text/html%0d%0aContent-Length: 0%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        %0d%0aHTTP/1.x 200 OK%0d%0aKeep-Alive: timeout=5%0d%0aConnection: Keep-Alive%0d%0aContent-Type: text/html%0d%0aContent-Length: 55%0d%0a%0d%0a<html><script>alert(document.location)</script></html>


But it doesn't work on Opera 8, Opera 8 works the way you would sort of expect a browser to work, in that it begins reading the stream from where it left off, and so we don't need to provide much whitespace:

http://www.dataplace.org/redir.html?url=index.html%0d%0aKeep-Alive: timeout=60%0d%0aConnection: Keep-Alive%0d%0aContent-Type: text/html%0d%0aContent-Length: 0%0d%0a%0d%0a%0d%0aHTTP/1.x 200 OK%0d%0aKeep-Alive: timeout=5%0d%0aConnection: Keep-Alive%0d%0aContent-Type: text/html%0d%0aContent-Length: 55%0d%0a%0d%0a<html><script>alert(document.location)</script></html>



3.0 Implementation Notes



If anyone wants to use this to use this to perform browser cache poisoning attacks (either to hide the suspicious URL or something similar) then the best way would probably be to check if the URL you are poisoning sends an Etag header and if so replicate that header so that when the browser sends a If-Modified-Since header, then the web server will honestly say it hasn't, if the resource you want to poison is a dynamic resource, you'll have to rely on the Cache-Control and Date headers alone (though these should be used along with the Etag header).


4.0 Conclusion



So as we can see, we don't need a proxy to implement interesting protocol oriented HTTP Response Splitting attacks, and hopefully someone with a deeper understanding of browsers than me can figure out why the above attacks aren't working in Firefox and Opera 9.

2 comments:

Anonymous said...

Hi!

Have you found why it is not working in firefox?

kuza55 said...

No, sorry, I never worked out why it wasn't working for Firefox. Maybe you'll have some more luck than I did.