Monday, April 30, 2007

XST sorta Lives! (Bypassing httpOnly)

Update 2: Amit Klein wrote in to remind me that you technically still can issue TRACE requests using XHR in IE6 SP2. By prepending some white space before the method it'll bypass the restriction (see below). I had forgotten about this little gem and would have thought MS would have fixed it long ago. Guess not or maybe they have. Either way I couldn't locate it. I also haven't done a lot of testing with IE7's XHR implementation (native right?), perhaps the same or other things can be found in there as well that could prove useful.

var x = new ActiveXObject("Microsoft.XMLHTTP"); x.open("\r\nTRACE","/",false); x.setRequestHeader("Max-Forwards","0"); x.send(); alert(x.responseText);Update 1: Jordan and Wladimir Palant noticed it right away! (Wladimir) "Wait, last time I checked Java wasn’t making HTTP requests through the browser. That means that neither cookies nor HTTP basic authorization will be visible in the response - only what you put in there yourself. Did that change?"

Apparently I made a very large oversight in my research. Wladimir and Jordan are absolutely right! Java handles the entire HTTP connection outside of the browser and hence does not send the cookies, headers, or anything else. So that data doesn't come back to be captured. Big mistake on my part. Can't believe I missed that! Very sorry. But I have another thought that I have to double check on....

Back in late 2002 Microsoft implemented the httpOnly cookie flag in Internet Explorer as a way to prevent XSS cookie theft by denying JavaScript from reading document.cookie. A couple of months later I authored a paper describing an attack I called Cross-Site Tracing (XST), or XSS++ if you prefer, as a bypass httpOnly (plus added some other good stuff). XST works by taking control of a victims web browser and forcing it to send an HTTP TRACE (method) to the target web server, typically via XmlHTTPRequest (XHR). Web servers supporting TRACE respond by placing the all data received in the HTTP request (request line, headers, post data) into the response body. Here’s an example of a simple TRACE request exchange:

Because the cookie becomes part of the response body, and not only found within document.cookie, JavaScript can access the data despite being tagged with httpOnly. As an additional benefit of XST, attackers can gain access to Basic, Digest, and NTLM Auth credentials located in HTTP request headers and typically out of reach of JavaScript. Simple. In response, all major web browser updated XHR to block the use of TRACE. Flash did the same. In years since I figured XST was dead on anything but an older browser, that is until late last week.

I was experimenting with some JavaScript calling Java APIs to perform Socket calls and then it hit me. If JavaScript and Flash can’t issue TRACE requests, maybe Java could. Turns out I was right, JavaScript can direct Java to issue TRACE requests out of the browser, but my PoC implementation was slow. With help from friendly neighborhood Java guru, Anurag Agarwal, we got some nice bookmarklet PoCs up and running. I’ll let Anurag take you through the code.

Please be mindful that the code is unstable and your results may vary due to browser support.

Approach 1 (Traditional Approach using earlier versions of jdk)

//Get the url on the browser’s address barvar l = document.location;

//Get the host name.var host =l.host.toString();

//Set the port to 80. We can also determine the port from the location barvar port = 80;

//Get the domain name of the host…check againvar addr = new java.net.InetAddress.getByName(host);

//Create a client socket to the server on the specified hostname and portvar socket = new java.net.Socket(addr,port);

//Open an output stream to send the request data to the server.var wr = new java.io.BufferedWriter(newjava.io.OutputStreamWriter(socket.getOutputStream(),"UTF8"));

//Open an input stream to read the response data from the server.var rd = new java.io.BufferedReader(new java.io.InputStreamReader(socket.getInputStream()));

In the traditional way (like the approach mentioned above), you'd now ask for the socket's input and/or output streams. The newer approach is using Channels. This approach is available with jdk1.4 or newer. With a channel you write directly to the channel itself. Rather than writing byte arrays, you read and write ByteBuffer objects. By default, this will read at least one byte or return -1 to indicate the end of the data, exactly as an InputStream does. It will often read more bytes if more bytes are available to be read.

16 comments:

I'm a bit confused though -- if Java is doing the entire connection itself, then you're not really going to be able to get the cookies or the digest credentials are you?

If the browser doesn't get into it the process of sending the data, it doesn't send along httpOnly cookies, or other juicy bits that you'd want to get access to, and thus you'd never see them in the trace response, right?

Ok, so if this is the case, that Java handles the entire HTTP request outside the browser, does this mean we can potentially deanonymize browser proxies? I just proxied myself through Paros (HTTP Proxy 8080 preference), then used this method to send a request. Didn't touch the proxy.

Yes, Java can be used as a de-anonymizer. Here is an example: http://algart.net/system/antianonymizetest.pl

More in-depth explanation is at http://webwarper.net/wwantianonymizerru.htm#wwaa (sorry, that's Russian but maybe the machine translation is readable). The whole concept was originally discussed here: http://xpoint.ru/forums/internet/theory/thread/33876.xhtml (yes, Russian again).

So what tricks could this still be used for? It seems like all the usual attacks against the browser won't work since it's not handling the response, but that it would still be perfectly functional for cache poisoning attacks. No need to even use the trace option. Still have to deal with same-origin though.

Hey Jordan, the one attack that immediately came to mind, de-anonymizing, someone had already found that I didn't know about. What I have learned from the exchange though is that there is a lot I don't understand about Java's capabilities in the browser and how JS can interact with it. Along with you line of thinking, perhaps another way to launch a response splitting attack or something like that... I'll have to think a lot about this.

I think Microsoft has just abandoned IE 6 SP2, and just concentrated all their efforts on IE 7, because other than that bug there is also a bug which allows you to view the set-cookie headers as well. And neither of those bugs worked in IE 7 when I tested them.....

Last week i visited you blog and it liked me. I found this post about using XST and javascript to obtain Basic, Dibgest credentials and bypass httponly cookie flag very interesting. I decided to do a proof of concept of your scripts. I done it with some changes but now i have a problem.The TRACE request that makes the script is:wr.write("TRACE / HTTP/1.1 \n");wr.write("Host: " + host + "\n");wr.write("\n\r");This request doesn´t includes Authorization parameters therefore neither the server response. I mean that if auth credentials headers is out of reach of javascript, we cannot include them in the TRACE request that we send to the server. In consecuence, the TRACE response from the server will not include these Auth parameters.You say that "As an additional benefit of XST, attackers can gain access to Basic, Digest, and NTLM Auth credentials located in HTTP request headers and typically out of reach of JavaScript." ¿How can it be possible? Maybe i am wrong or i´m missing something.

I obtain the TRACE server response including de "xst:test" parameter i use in the request but not the authenticaton parameters.I proved (it´s a proof of concept) with Apache/2.2.3 and the client is Firefox 2.0.0.14.This is the code with wich i achieved it (with workmate help out):

About Me

Jeremiah Grossman's career spans nearly 20 years and has lived a literal lifetime in computer security to become one of the industry's biggest names. He has received a number of industry awards, been publicly thanked by Microsoft, Mozilla, Google, Facebook, and many others for his security research. Jeremiah has written hundreds of articles and white papers. As an industry veteran, he has been featured in hundreds of media outlets around the world. Jeremiah has been a guest speaker on six continents at hundreds of events including many top universities. All of this was after Jeremiah served as an information security officer at Yahoo!