Wednesday, 12 March 2008

Defeating the Same Origin Policy: Part I

So last week Sun released updated versions of the Java Runtime Environment and with them, a host of Sun Alerts. These are neatly summarised on the Sun Security blog. Over the next few posts I am going to discuss the issues that I had a hand in reporting.


The first one I'm going to tackle is Sun Alert 233324, "A Security Vulnerability in the Java Plug-in May Allow an Untrusted Applet to Elevate Privileges"; NGS advisory is here. Your first thought might be that we achieve the elevation of privilege through a buffer overflow - I blogged on buffer overflows in the JRE a while back and if you read over the alerts Sun published last week, you'll see Java Web Start had several overflows fixed (I'll be discussing Sun Alert 233323, "Multiple Security Vulnerabilities in Java Web Start May Allow an Untrusted Application to Elevate Privileges" at a later date). However, if you read the brief description of this bug you'll see its a little more intriguing:


A security vulnerability in the Java Plug-in may allow an applet that is downloaded from a website to bypass the same origin policy and leverage this flaw to execute local applications that are accessible to the user running the untrusted applet.


I'm going to split the analysis of this issue into two parts. In this post I'm going to cover "bypassing the same origin policy"; in the next post I'm going to cover "leveraging this flaw to execute local applications". If anyone figures out the second part before I post it, add a comment or send me an email :)


So, part one, bypassing the same origin policy. The same origin policy effectively underpins browser security. It means that resources loaded from one origin cannot get or set properties of a resource from a different origin. The web app sec guys are always going on about this and coming up with new ways of bypassing the restriction. I find this research interesting but give me a browser 0day anyday (so its kinda ironic that I'm posting on it!). In the same way that client-side scripting languages enforce the same origin policy, Java implements a sandbox to limit network connectivity in untrusted applets. This is documented in the Java Security FAQ.


In a nutshell, unsigned applets are not allowed to open network connections to any host, except for the host that provided the .class files (either the host where the HTML page came from, or the host specified in the codebase parameter in the applet tag, with codebase taking precendence). Quite simply, if we try to create a connection to foo.com from an applet that did not originate from the machine foo.com, it will fail with a security exception.*


Applets are instantiated via the <APPLET> or <OBJECT> HTML tag. Both the code and codebase attributes/parameters must be set e.g. <APPLET code="foo" codebase="http://bar"/> will cause foo.class to be loaded from http://bar. The code that loads the class creates a URL object via the following constructor:


public URL(URL context,
String spec)
throws MalformedURLException


This constructor has an interesting property, namely:


If the authority component is present in the spec then the spec is treated as absolute and the spec authority and path will replace the context authority and path. If the authority component is absent in the spec then the authority of the new URL will be inherited from the context.


This effectively means that executing:


URL url1 = new URL("http://baz");
URL url2 = new URL(url1, "http://bar");


returns us url2 representing http://bar. So what happens if we instantiate an applet as follows:


<APPLET code="http://baz/foo" codebase="http://bar" />


Though the answer is probably obvious by now, we can use JSwat, the GUI Java debugger frontend, to confirm things.


Briefly, the steps are:


  • Configure JSwat for applet debugging (its easiest to specify "suspend=y" so the debugger doesn't run away).

  • Set a breakpoint on the URL constructor and hit go. The breakpoint will fire quite a few times (we could set a conditional breakpoint to avoid this); we can view the parameters to the constructor via the Variables pane.

  • Eventually we should see the java.net.URL parameter holding the specified applet codebase (http://bar) and the java.lang.String parameter holding the specified code attribute (http://baz/foo). The screenshot below illustrates this for my internal PoC; the codebase was http://www.google.com and the code parameter was http://2130706433/connect (the reason for using 2130706433 will be explained shortly).


JSwat... it swats bugs.


So now we can definitively answer the question: it will load foo from baz but report the codebase as bar. We've defeated the same origin policy; our applet can connect to bar even though it was loaded from baz.


Of course, the devil is in the detail... there are some complications to get this attack working. Firstly, if we specify a code parameter containing a '.', e.g.:


<APPLET code="http://baz.com/foo" codebase="http://bar" />


then an internal canonicalisation routine is triggered, converting '/' characters into '.' so we end up with a URL looking like "http:..baz.com.foo" and the attack fails. The easiest way round this limitation is to use the decimal representation of an IP address, as is apparently common with spammers. If you're too lazy to do the maths, there's an online converter here. So our code parameter will look like:


<APPLET code="http://2130706433/foo" codebase="http://bar" />


The final complication is that the Java plugin loads foo.class expecting to find a class called "http://2130706433/foo". This is easy to solve - we compile our class with a class name of "aaaaaaaaaaaaaaaaaaaaa" and use a hex editor to replace this string with "http://2130706433/foo" (the compiler doesn't like it but the JVM will load it).


That concludes the first post on this issue. Next time I'll cover using the same origin bypass to escape the sandbox.




Cheers

John




* A while back I posted an advisory on another same origin bypass that allowed an applet loaded from a remote location to connect to localhost, thereby allowing it to attack local services.

1 comment:

pdp said...

wow, great analysis john... keep it comming.