Saturday, February 23, 2008

HTTP Range & Request-Range Request Headers

For those that haven't heard of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Range header, here's a link: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2

For everyone who can't be bocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365red reading a link; essentially cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Range header is what you use to ask a server for a part of a response, racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole response; it's what makes resumeable downloads possible over http.

Anyway, anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r piece of research I presented at 24c3 is pretty simply, but racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r useful:

Flash



If Flash were to allow us to send a Range header, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we would be able to get things sent to us completely out of context.

Until Apache 2.0 this header was only used when requesting static files, so it would not influence a typical XSS, however if we have an application such as vBulletin which protects against FindMimeFromData XSS attacks by searching cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first 256 bytes for certain strings, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we can simply place our strings after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first 256 bytes and get Flash to send a header which looks like this:
Range: bytes=257-2048
To have unscanned data sent in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first 256 bytes, leading to XSS.

However since Apache 2.0 (and possibly in ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r webservers, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're irrelevant to this post), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Range handling code is implemented as a filter; this means that it is applied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 output of every request, even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are dynamic requests.

This means that if we were to have a normally unexploitable XSS condition where our use input was printed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page inside an attribute with quotes eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r encoded or stripped, but all ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r metacharacters left intact, or an xss filter did not encode cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 html attributes you had at all like so:
”>link

Then we could use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Range header to request only our unencoded portion which would result in XSS.

Now, why is this important since Flash has never let anyone send a Range header?

Well, while looking through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apache source code I found this beautiful snippet:
if (!(range = apr_table_get(r->headers_in, "Range"))) {
range = apr_table_get(r->headers_in, "Request-Range");
}


Which essentially says that if you can't find a Range header, look for a Request-Range header, and untill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest version of Flash (9,0,115,0), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Request-Range header was not blocked. (I had hoped this would be unpatched when I presented it, but you can't really hope for much when you sit on a bug for almost half a year...)

Firefox


Now cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 part I didn't present. In Firefox 3 Firefox implemented cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new Cross-Site XMLHttpRequest which, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name suggests, lets you make cross-site requests and read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 responses.

There is some documentation here: http://developer.mozilla.org/en/docs/Cross-Site_XMLHttpRequest

The part of those specs which is relevant to this post is that you can allow Cross-Site XMLHttpRequests by including an XML preprocessing instruction; however you can't just XSS it onto cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page as usual because it needs to be before any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data.

However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XMLHttpRequest object allows you to append both Range and Request-Range headers. And by appending a Range header we can get our XSS-ed instruction to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 response, and read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 response.

The limitations with this are fairly strict; as far as I can tell, you cannot add to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XHR policy cache with xml instructions, only with headers, and if you attempt to request multiple ranges, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 multi-part boundary which begins cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 response will be sent before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 xml instruction, and so it will not be parsed, so you can only get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page that are after your XSS point. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand I wasn't even able to get non-GET requests to work with server-side co-operation, so take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se with a handful of salt.

On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 up side, this does bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 .NET RequestValidation mechanism since that does not flag on

3 comments:

Script Hacker said...

Nice!

Anonymous said...

Just a reply to FindMimeFromData():
http://msdn.microsoft.com/en-us/library/ms775147.aspx


The function will return cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server content-type header if it doesn't recognize it. So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server might use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header "image/leave-me-alone" instead of "image/gif" and IE wouldn't change try to guess it.

Then, because it fails to find it, it will look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 extension - and (probably) correctly use image/gif.

I haven't tested it, but this is how I understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 documentation. It is an ugly hack anyway, but better this than checking first 256 bytes or copying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 image...

Anyway, just an idea, thought I would share. :)

Nice blog!

Anonymous said...

I can't reproduce this bug in 6.0.2900.2180.xpsp_sp2_gdr - it might be fixed. Finally. :)

Best,

Andr3w