Saturday 21 June 2008

A Different Form of JAR Hell

In my last post I used a Java applet to steal password hashes. Part two, covering NTLMv2, is on its way. Today however, I'm going to discuss SunSolve #233323 - a vulnerability that was fixed in the March updates to the JRE. Anyone who caught my ToorCon talk will have already heard me discuss this issue.


Java Web Start has provision for resources, signed JAR files that contain either Java classes or native libraries that can be cached for use by one or more applications. JARs containing Java classes are extracted as per the usual Java caching mechanism (i.e. written to disk using randomly generated names) whereas native libraries are extracted with their original filenames. Interestingly filenames can include parent path sequences (e.g. ..\..\..\..\test.txt). This means that "nativelibs" can be written outside the cache folder. But that's ok because nativelib resources need to be signed and therefore explicitly trusted by the user, right?


Not exactly. Take a look at the following code snippet, which resembles the vulnerable Java Web Start code, and see if you can spot the bypass (it's not exactly obvious):


try
{
// Open the JAR file specifying true to indicate
// we want to verify the JarFile is signed.
JarFile jf = new JarFile(UserSuppliedFile, true);

Enumeration e = jf.entries();
while (e.hasMoreElements())
{
ZipEntry ze = (ZipEntry) e.nextElement();
InputStream i = jf.getInputStream(ze);
byte b[] = new byte[i.available()];
i.read(b);

// Call our method to write the bytes
// to disk

WriteFileToDisk(ze.getName(), b);
}
}
catch (SecurityException se)
{
// Some sort of signature verification error
System.out.println("Security Error: " + se.toString());
}
catch (IOException ioe)
{
System.out.println("File Error: " + ioe.toString());
}


If you spotted the problem, well done! If not, here's a hint courtesy of an IBM article on signed JARs:


Each signer of a JAR is represented by a signature file with the extension .SF within the META-INF directory of the JAR file. The format of the file is similar to the manifest file -- a set of RFC-822 headers. As shown below, it consists of a main section, which includes information supplied by the signer but not specific to any particular JAR file entry, followed by a list of individual entries which also must be present in the manifest file. To validate a file from a signed JAR, a digest value in the signature file is compared against a digest calculated against the corresponding entry in the JAR file.


What if a file doesn't have a corresponding manifest entry? It turns out the above code will happily call WriteFileToDisk anyway and there'll be no exception thrown. We can use this bypass to append a file to a signed resource and have it drop a java.policy file in the user's home directory allowing applets and Web Start applications to do bad things.

Let's take a look at how the Jarsigner tool that ships with the JDK validates signed JARs. Jarsigner correctly detects JARs containing both signed and unsigned content:



The code snippet below shows the enumeration of ZipEntrys; it's taken from sun.security.tools.JarSigner:


Enumeration e = entriesVec.elements();

long now = System.currentTimeMillis();

while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
String name = je.getName();
CodeSigner[] signers = je.getCodeSigners();
boolean isSigned = (signers != null);
anySigned |= isSigned;
hasUnsignedEntry |= !je.isDirectory() && !isSigned
&& !signatureRelated(name);


The code retrieves the entry's CodeSigners; if there are none the entry is deemed unsigned.


As an aside, it's actually possible to fool Jarsigner. Take a look at the signatureRelated method, which is called above:


    /**
* signature-related files include:
* . META-INF/MANIFEST.MF
* . META-INF/SIG-*
* . META-INF/*.SF
* . META-INF/*.DSA
* . META-INF/*.RSA
*/
private boolean signatureRelated(String name) {
String ucName = name.toUpperCase();

if (ucName.equals(JarFile.MANIFEST_NAME) ||
ucName.equals(META_INF) ||
(ucName.startsWith(SIG_PREFIX) &&
ucName.indexOf("/") == ucName.lastIndexOf("/"))) {
return true;
}


Jarsigner ignores unsigned files that start with the prefix "META-INF/SIG-":



Anyway, back to the Web Start issue. Soon after discovering this bug I realised it was effectively moot for I hadn't seen any security dialogs even when working with fully signed JARs. It turned out there were none. Ever. You could simply even use a self-signed JAR! Still, it's a great example of a managed language providing a simple interface (JarFile) that masks a complex implementation; if the contract between the caller and the callee is not clearly defined (however simple the interface), developers can write insecure code without knowing it.


So that's it for now. There's also some interesting behaviour when loading applets containing signed and unsigned content but I'll save that for another day.



Cheers

John

p.s. In case you were wondering, JAR hell is Java's form of DLL hell.

Thursday 5 June 2008

Stealing Password Hashes with Java and IE





Consider for a moment the state of client-side bugs 5 or 6 years ago. Attacks such as this, a multi-stage miscellany of IE and Mediaplayer bugs that resulted in the "silent delivery and installation of an executable on the target
computer, no client input other than viewing a web page" were reported with regularity. Gradually these type of attack gave way to exploitation of direct browser implementation flaws such as the IFRAME overflow and DHTML memory corruption flaws. So what has become of the multi-stage attacks - have they become redundant? The answer to this, which I'm sure you can guess, is a resounding "no" and will be emphatically demonstrated in my upcoming Black Hat talk "The Internet is Broken: Beyond Document.Cookie - Extreme Client Side Exploitation", a joint double session presentation co-presented by Billy Rios, Nate McFeters and Rob Carter.


As a teaser for that, I'm going to revisit an old attack - pre-computed dictionary attacks on NTLM - and discuss how we can steal domain credentials from the Internet with a bit of help from Java. I'm going to split it into two posts. In this post we'll apply the attack to Windows XP (a fully patched SP3 with IE7). In my next post we'll consider its impact on Windows Vista.


NTLM Fun and Games

The weaknesses of NTLM have long been understood (and documented and presented) so I'm not going to cover them in detail here. For the interested reader I recommend this L0phtCrack Technical Rant and Jesse Burn's presentation from SyScan 2004, NTLM Authentication Unsafe. The pre-computed dictionary attack on NTLM that we are interested in has also already been implemented in tools such as PokeHashBall. In a nutshell, this attack works as follows:


  1. Position yourself on the Intranet.

  2. Coerce a client, either actively or passively, into connecting to a service (such as SMB or a web server) on your machine.

  3. Request authentication and supply a pre-selected challenge.

  4. Capture the hashes from the NTLM type 3 message and crack them using rainbow tables or brute force.

A requirement of this attack is for the attacker to be located on the Intranet. There have been suggestions on how to remove this necessity; see this post for a discussion on DNS rebinding as a potential solution. Let's take a step back though and begin by reviewing IE's criteria for determining whether a site is located on the Intranet or the Internet:



By default, the Local Intranet zone contains all network connections that were established by using a Universal Naming Convention (UNC) path, and Web sites that bypass the proxy server or have names that do not include periods (for example, http://local), as long as they are not assigned to either the Restricted Sites or Trusted Sites zone


Let's focus on names that do not include periods. As Rob Carter has pointed out, there are more than a few home/corporate products that install web servers bound to localhost and since http://localhost meets the above criteria, XSS in these products let's us control content in the Local Intranet Zone. If we were therefore able to fully control a web server on the local machine, headers and all, and we were able to cause IE to connect to it, we could ask IE to authenticate allowing us to use a pre-selected challenge in order to carry out a pre-computed dictionary attack. But how does a malicious website run a web server on your machine? This is where the Java browser plugin comes into play...


A Web Server in Java

There is nothing to stop an unsigned Java applet from binding a port provided the port number is greater than 1024. The same origin policy, which I've discussed previously is enforced when the applets accepts() a connection from a client; only the host from which the applet was loaded is allowed to connect to the port. If a different host connects, a security exception is thrown, as shown below.



This means that if we can make the applet think it was loaded from localhost, we can bind a port and act as a web server, serving requests originating from localhost. I have previously covered two ways of manipulating the applet codebase (the verbatim protocol handler and defeating the same origin policy), but these flaws are now patched. We can accomplish the same effect on the most recent Java browser plugin by forcing content to be cached in a known location on the file system and by referencing it using the file:// protocol handler*. So if we know that our class was stored at c:\test.class for example, we could load it via the following APPLET tag (the default directory is the desktop hence the ..\..\..\):


<APPLET code="test" codebase="file:..\..\..\"></APPLET>


The result of loading content from the local machine is that a SocketPermission is added allowing the applet to bind a port and accept connections from localhost.


So this attack effectively boils down to caching content in a known location. The Java applet caching mechanism stores content at %UserProfile%\Application Data\Sun\Java\Deployment\cache (or equivalent under Protected Mode on Vista). Class files and JARs are given randomly generated names (and that's SecureRandom before you ask). There are, however, multiple ways of silently getting content onto the local machine with a fixed name. And thats all I'm going to say for now; we'll be addressing this topic further in our Black Hat talk :)


The Windows Firewall

What about the Windows firewall you may ask. The trick is to make sure we bind to 127.0.0.1 only as doing so will not trigger a security dialog. This is accomplished in Java as follows:


ServerSocket ss = new ServerSocket(port, 0, InetAddress.getByName("127.0.0.1"));


Actually it turns out that on Vista in order for our web server applet to work at all, we must call the ServerSocket(int port, int backlog, InetAddress bindAddr) constructor anyway rather than simply ServerSocket(int port). Calling ServerSocket(int port) will bind using IPv6 as well as IPv4; when we then point IE to http://localhost, it will connect to the IPv6 endpoint and throw the following exception:



The reason for this is that the Java code adds a SocketPermission for 127.0.0.1 which is obviously IPv4 only.


Putting it all together

The code for the web server applet is very simple. We needn't implement a full, multi-threaded web server; all we really need to do is send an HTTP/1.1 401 return code with a WWW-Authenticate header of NTLM in response to IE's first request. This will trigger the NTLM exchange of base-64 encoded messages. Since NTLM authenticates connections we must remember to send a Content-Length header (even if there's no content, i.e. Content-Length: 0) to ensure the connection stays open. There are several resources out there that provide detailed NTLM specs and examples. I used this one.


The HTML page that we use to tie the attack together consists of multiple hidden IFRAMEs: firstly to load the Java browser plugin and cache the content, then to launch the web server applet from file://, then to make a request to http://localhost. For my PoC I created a 2nd applet to display the progress of the attack and to allow me to easily copy and paste the hashes out of the browser; a sample capture is shown below. Obviously in a real attack we'd want to ship the hashes off the victim's box either via JavaScript or Java.



Once we have the hashes, we can use rainbow tables to crack the first 7 characters of the LM response or brute force via a password cracker that can handle captured NTLM exchanges, such as John the Ripper with this patch. We can then brute force the remainder of the password. For anyone interested in the approaches to cracking NTLM, I recommend warlord's Uninformed paper, Attacking NTLM with Precomputed Hashtables.



Summary

So to summarise the above, if a user on a domain joined XP machine with the Java browser plugin visits a malicious website with IE, the malicious website can steal their username, domain name and a challenge response pair in order to carry out a pre-computed dictionary attack, likely revealing the user's password in a short time.


Once again this is not a new attack - there are a good many tools that implement the well known NTLM attacks such as SMBRelay, ScoopLM and Cain & Abel. The delivery and execution of this attack, however, demonstrates that multi-stage client-side attacks are alive and well...


That's it for now. Next time we'll consider how this attack applies to Vista, which enforces the more secure NTLMv2 by default.




Cheers

John


*Note that unlike Flash, Java implements its own protocol handlers rather than relying on the browser's.