Tuesday, May 19, 2009

Write once, own everyone, Java deserialization issues

EDIT3: This vulnerability has been nominated for a Pwnie Award for "best client-side bug"!
EDIT 2: On June 15th 2009, Apple has updated Java on MacOS X with a version that fixes this issue.
EDIT 1: this has been featured on
Slashdot, Ars Technica, ZDNet, OSnews and many others. The focus was on the fact that this is still not fixed on MacOS X. However, keep in mind that you may still be at risk if you use another operating system (Windows, Linux), especially with an outdated version of Java, which is very common. You should disable Java applets in your browser if you can, or at least consider using NoScript.

It is time to talk about my favorite client-side vulnerability ever. Surprisingly (if you know me), this is a Java vulnerability, or rather a class of Java vulnerabilities that allows to completely bypass the Java sandbox and execute arbitrary code remotely in Java enabled web browsers.
This was found by Sami Koivu. He reported the first instance of it (CVE-2008-5353) to Sun on August 1st 2008 and this instance has been fixed by Sun on December 3rd 2008. These vulnerabilities are both technically interesting and have a lot of impact.

Since they share core classes, OpenJDK, GIJ, icedtea and Sun's JRE were all vulnerable at some point. And unfortunately, this vulnerability is still not fixed everywhere yet.

I've been wanting to talk about this for a while. I was holding off, while Apple was working to patch this vulnerability. Unfortunately, it is still not patched in their latest security update from just a few days ago. I believe that since this vulnerability has already been public for almost 6 months, making MacOS X users aware that Java needs to be disabled in their browser is the good thing to do.

As a side note, Sami Koivu and I paired at latest Pwn2own (his vulnerability, my exploit) and owned both Firefox and Safari on MacOS X on day one (Java is there and enabled by default on MacOS X). Unfortunately it fell out of the challenge criterions because the vulnerability had already been reported to Sun and I had already pinged Apple in January about it.

So let's talk about the first reported instance of this class of vulnerabilities, the Calendar deserialization vulnerability.

For legacy reasons, the deserialization of the sun.util.calendar.ZoneInfo object in a java.util.Calendar has to be fine tuned, so the readObject() method in the Calendar class will handle it. However, an applet cannot access sun.util.calendar.ZoneInfo because it is inside "sun" and anything in "sun" has to be trusted for the Java Applet security model to hold.
For this reason the code responsible for the ZoneInfo deserialization has to run with privileges. The code in java.util is trusted and can get more privileges by using a doPrivileged block:
   try{
ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return input.readObject();
}
});
if (zi != null) {
zone = zi;
}
} catch (Exception e) {}

So what does this buy us ? We can craft an input and deserialize objects from it. By deserializing a Calendar, we can get a ZoneInfo object deserialized in a privileged context. Wait! How do they check this is a ZoneInfo object? They let Java's type checking do this for them. So if we carefully craft our input, we can get an arbitrary object deserialized but it'll not get affected to zi unless it's a valid ZoneInfo.

To exploit this, let's find a class that we would be forbidden to instantiate in an Applet because it would allow us to escape from the Java sandbox. The RuntimePermission class is a great source of inspiration. A ClassLoader seems to be exactly what we are looking for! Let's make our own ClassLoader sub-class and override the readObject() method. This method will be called during deserialization. In this method we can affect ourselves (this) to a static variable so that our shiny new ClassLoader doesn't get garbage collected and so that we can use it later.

With our own ClassLoader we can define classes with our own ProtectionDomain (with arbitrary privileges). That's it!

There is more work to do. The overall exploit can be quite complex (mine is over 500 lines but you can make a simpler version) but you get the basic idea.
Also there is the problem of manually crafting the malicious serialized file. In a first version I did this manually by re-implementing the Serialization protocol. Later I found a nice trick: by overriding replaceObject(), you can let Java do all the work for you.

I've mentioned that this was a class of vulnerabilities: the reason is that with this design, every time Java code deserializes an attacker-controlled input in a privileged context, it's a security vulnerability. Sun fixed the Calendar vulnerability (see this patch) by creating a new accessClassInPackage.sun.util.calendar privilege and restricting the doPrivileged block to this, so they didn't fix the whole class of them (more on this in a later post).

That's it for the technical part.

Now why do I think this client-side arbitrary remote code execution vulnerability is more interesting that most others?

First, according to Adobe and Sun, Java is available in 80% to 90% of all web browser, which makes it a nice target.

Secondly, for various reasons, Java is usually poorly updated:
  • The Sun Java update mechanism isn't tied to the operating system update system on the Windows platform. Personal users and companies don't update it often, some of them do have processes in place to deal with Microsoft's patch Tuesdays but don't for other software updates.
  • Many companies are using web applications or Java software that rely on a specific Java version. It may be tedious to update Java because it would break many things. This may be the reason why Apple's Java updates are so infrequent.
  • Some Linux distributions don't support Sun's JRE (proprietary software) despite making it available. When I asked Ubuntu to fix this vulnerability, they fixed OpenJDK quickly but told me the Sun JRE was not supported (despite being available by default on the latest LTS Ubuntu release).
Third, and this is the important point: most other client-side vulnerabilities that can lead to arbitrary code execution, including other Java vulnerabilities are memory corruption vulnerabilities in a component written in native code. Exploiting those reliably can be hard. Especially if you have to deal with multiple operating system versions or with PaX-like protections such as DEP and ASLR.
This one is a pure Java vulnerability. This means you can write a 100% reliable exploit in pure Java. This exploit will work on all the platforms, all the architectures and all the browsers! Mine has been tested on Firefox, IE6, IE7, IE8, Safari and on MacOS X, Windows, Linux and OpenBSD and should work anywhere.

This is close to the holy grail of client-side vulnerabilities.

So MacOS X users, please disable Java in your web browser.
Others: make sure you have updated Java and still disable it in your web browser: it's a huge attack surface and it suffers from many other security vulnerabilities.
Moreover, even without taking into consideration Java vulnerabilities themselves, since the Java plugin allocates all memory as RWX and doesn't opt-in for randomization, a Java applet can be used to bypass ASLR and non executability (DEP on Windows) in browser exploits.

You can also get some information about this vulnerability on Sami Koivu's blog, here and here and a time line for some of the bugs he reported to Sun here.

32 comments:

  1. Landon Fuller also wrote an exploit for this vulnerability and blogged about it there

    ReplyDelete
  2. As far I know, the Ubuntu default is OpenJDK. The sun-java6* packages are in multiverse, i.e. not really supported. See http://www.ubuntu.com/community/ubuntustory/components :

    "The "multiverse" component contains software that is "not free", which means the licensing requirements of this software do not meet the Ubuntu "main" Component Licence Policy.

    The onus is on you to verify your rights to use this software and comply with the licensing terms of the copyright holder.

    This software is not supported and usually cannot be fixed or updated. Use it at your own risk. "

    ReplyDelete
  3. Sweet, I didn't even realize java was enabled by default in safari. Now wishing I'd known before viewing this article, and why is my location bar flashing?

    I do like the write once sploit everywhere notion repeated here and wish people would stop buying into all of Java security hype.

    ReplyDelete
  4. Some weeks ago Apple posted a new preview of the Java package (1.4/5.0/6.0)l It is available via the dev-site; I wonder if there are some relevant fixes there (but there is a NDA).

    ReplyDelete
  5. You're location bar is "flashing" because the page is reloading. You think it's flashing because you're an idiot.

    ReplyDelete
  6. So has anyone tried to contact Security Focus about this vulnerability to get them to force Apple to patch this hole???

    ReplyDelete
  7. If the vulnerability is present in JREs, isn't it Sun's responsibility to fix it instead of Apple's ?

    ReplyDelete
  8. If you managed to read the article, you would see that the JRE is fixed, and has been for a long time. It's just Apple that hasn't sent a updated version to the Mac users yet. So it's Apple's responsibility.

    ReplyDelete
  9. Sweet Jesus! Thanks for the info.

    ReplyDelete
  10. So why does Apple have their own Java? Shouldn't this raise a ruckus about Apple's powergrabs and get them to stop being so controlling?

    ReplyDelete
  11. Somebody who writes 'your' as 'you're' as in 'You're location bar is "flashing"' and then proceeds to call someone else an idiot is surely one idiot that has been already infected.

    ReplyDelete
  12. The flashing location bar is due to this Javascript that Blogger seems to insert. I think it's trying to track how long people take to scroll down the page initially. Irritating...

    (function() { var a=window;function f(e){this.t={};this.tick=function(d,b,c){var i=c?c:(new Date).getTime();this.t[d]=[i,b]};this.tick("start",null,e)}var g=new f;a.jstiming={Timer:f,load:g};try{a.jstiming.pt=a.external.pageT}catch(h){};a.tickAboveFold=function(e){var d,b=e,c=0;if(b.offsetParent){do c+=b.offsetTop;while(b=b.offsetParent)}d=c;d<=750&&a.jstiming.load.tick("aft")};var j=false;function k(){if(!j){j=true;a.jstiming.load.tick("firstScrollTime")}}a.addEventListener?a.addEventListener("scroll",k,false):a.attachEvent("onscroll",k); })();

    ReplyDelete
  13. Apple has their own Java because they wanted it that way and Sun said ok you take care of it.

    ReplyDelete
  14. JRE is not written for BSD so apple has to rewrite it for their OS, which runs on BSD.

    ReplyDelete
  15. You don't say whether the vulnerability applies to both the Java 5 and 6 VMs, or just the default (Java 5).

    Can you give any idea whether swapping to Java 6 (for Intel users) using Java Preferences would patch this issue?

    ReplyDelete
  16. In my experience, changing your preferences to use Java6 has no effect at all. The system seems to completely ignore the Java6 installation which is pretty annoying.

    ReplyDelete
  17. It has no effect (at least for the plugin) because it's 64bit and the browsers are all 32bit so they continue to use the 32bit version of Java.

    ReplyDelete
  18. Is that for both applications and applets?

    ReplyDelete
  19. OK - just seen that second reply. Hadn't looked into the 64-bit restrictions of Java6 (or rather had made a very cursory search on it).

    See why people are pretty frustrated by the Java 6 situation.

    ReplyDelete
  20. My eyes started to bleed 2 paragraphs in due to your awful page design.

    Thank god who does not exist for the Readable bookmarklet.

    ReplyDelete
  21. I tried the POC http://landonf.bikemonkey.org/static/moab-tests/CVE-2008-5353/hello.html in Google Chrome for Mac OS X. /usr/bin/say did not execute when POC was ran in Chrome but did execute in Safari, Webkit, Firefox, etc. Is Chrome helping to protect me here?

    ReplyDelete
  22. "My eyes started to bleed 2 paragraphs in due to your awful page design." lol

    I actually like the design

    ReplyDelete
  23. > So why does Apple have their own Java? Shouldn't this raise a ruckus
    > about Apple's powergrabs and get them to stop being so controlling?

    Jesus, prejudge much? Apple said 'hey, we want Java on the Mac' and Sun said 'well, WE sure aren't going to code it. But I guess if you want our source code you can make your own.' (This was before Sun opened up the Java source, BTW.)

    What were they supposed to have done?

    -fred

    ReplyDelete
  24. Can someone give me a real world example of Java being used in a situation that is not equally suited with a native application on your OS of choice? I just don't see Java being used anymore.

    ReplyDelete
  25. It's used a lot. What your question has to do with this vulnerability ... nobody will ever know.

    ReplyDelete
  26. What is Java good at really ?
    Many Java apps are still non-portable and work exclusively on MS-Windows...
    Looks like Tcl would actually be a better choice for client-side UIs...

    ReplyDelete
  27. "Many Java apps are still non-portable and work exclusively on MS-Windows..."

    hmm, if that would be the case, Sun wouldn't have bothered to create a runtime system (at least back in the day)

    ReplyDelete
  28. Wow - amazing to see the 'Java is useless' crowd still crawling out from under their stones.

    A number of my favourite desktop apps - Eclipse, JEdit, Azureus/Vuse - are written in Java, and look/work better than the vast majority of Windows apps. The only reason I don't use more Java apps on the Mac is that Cocoa-based ones are so fantastic.

    And as for the "Java only run on Windows" line - that hasn't been true for 5 or more years, so why come out with it? You're only making yourself look stupid.

    ReplyDelete
  29. "Saying that Java is good because it works on all platforms is like saying anal sex is good because it works on all genders"

    http://www.storm-consultancy.com/blog/other/classic-programming-quotes/

    ReplyDelete
  30. Turn off Java in your browser as I have done on my Mac and you will quickly discover how many sites use it. Not all, but enough.

    ReplyDelete
  31. "Jesus, prejudge much? Apple said 'hey, we want Java on the Mac' and Sun said 'well, WE sure aren't going to code it. But I guess if you want our source code you can make your own.' (This was before Sun opened up the Java source, BTW.)

    What were they supposed to have done?"

    They should have went and died in a corner with all their crap products and marketing.

    ReplyDelete