Wednesday, February 25, 2009

Java SE Security - Part I

I'm starting a section here outlining a few basic ways for analyzing Java SE security in a pure Java sense. That is: Java code which might escape from the security sandbox, most commonly set up for Java applets.

This first part will deal with the method AccessController.doPrivileged().

What does it do?

It is used to execute a piece of code in a privileged context. The different variations of the method take a PrivilegedAction, or PrivilegedExceptionAction instance as a parameter and execute the run method of that action.

Why do we need that?

All the code that comes from the jre/lib (rt.jar, etc) is already privileged. Even when executed in the context of an applet that code has the privileges to read/write files, open network connections, execute processes and so on.. as long as there is no untrusted code on the calling stack.

Wait, what? What does that mean?

All the code in the JRE that does stuff that is considered privileged is armed with a call to the SecurityManager to ask if the caller has sufficient privileges to call it. As an example, let's look at File.delete():
public boolean delete() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkDelete(path);
}
return fs.delete(this);
}
So the first thing the method does is that it tries to obtain the currently installed SecurityManager and checks if it isn't null. Null in this case means there is no SecurityManager installed and everything is pretty much allowed. In the case of an applet, there will always be a SecurityManager, and next the code asks the SecurityManager if deleting at the given path is allowed. If the SecurityManager objects, it will throw a security exception. If no exception is thrown, the file actually gets deleted.

The SecurityManager checks every class that is on the calling stack (the method that called the method that called the method...) and makes sure every single of these classes is allowed to delete that file. So, if you try that from an applet's start method, that method will be on the calling stack and since your applet is not allowed to delete files, the SecurityManager will throw an exception.

So how does doPrivileged come into play?

There are some operations that have to be allowed, even though there is some untrusted code on the calling stack. A simple example is that many JRE methods require access to system properties that control their functionality. So the code that reads the system property is wrapped in a doPrivileged call and even if the method was executed from an applet, the operation is allowed.

This is actually intelligent. The potentially dangerous code which could introduce security vulnerabilities is wrapped up in and tagged by the doPrivileged blocks. This makes it pretty straightforward to audit them.

How does one find the doPrivileged blocks?

My preferred tool of the trade is Eclipse (http://www.eclipse.org/). To be effective, one needs the source code. The JDK normally comes with a src.zip, containing the source code of the public API classes and some other classes. However, to get some sources one needs to dig deeper.

Eclipse has a nice piece of functionality called "Call Hierarchy", which searches all the places where a given method is called, allowing you to dig deeper, viewing the callers' callers, and so on. So you could open the AccessController class, select the doPrivileged method and view it's call hierarchy.

How does one tell what's secure and what isn't?

Most of the doPrivileged blocks are small, precise, don't trust any input and do exactly one determined thing. However, this isn't always the case.

For example, public class sun.util.calendar.ZoneInfoFile has a private static method readZoneInfo file, which takes a filename String as a parameter and returns the file contents as a byte array. The file contents are read in a doPrivileged block.

Something like this:

package sun.util.calendar;

...

public class ZoneInfoFile {

...
private static byte[] readZoneInfoFile(String fileName) {

...
buffer = (byte[]) AccessController.doPrivileged(new PrivilegedExceptionAction() {

...
}
...

}


Things to consider:
  • It's a public class and therefore accessible outside it's package for all
  • It's not a serializable class
  • It's a non-final class, and it has an accessible constructor, so it could be subclassed.
  • It's in a sun. package and therefore cannot be accessed from an applet
  • The method is private and therefore cannot be invoked from another class

But:
  • The method is called from another private static method createZoneInfo of the same class
  • createZoneInfo is called from a public static method getZoneInfo (still inaccessible because of the package)
  • getZoneInfo is called from a public static method getTimeZone of the same class
  • getTimeZone is called from a private static method getTimeZone of the public class TimeZone (which resides in the accessible package java.util)
  • getTimeZone is called from a public static method getTimeZone of the public, accessible class java.util.TimeZone

So this path actually allows calling the doPrivileged block, passing any filename for it to read. However due to the long path, the return is no longer a byte array and there are a lot of validations along the way. In any case this illustrates the process of analyzing a piece of code.

Monday, February 23, 2009

Correction on how Sun fixed the Calendar bug

Many thanks to Julien Tinnes for pointing this out to me.

In a previous post, I had said:
What they did fix, and on this I fully agree is that now when a serializable subclass of a non-serializable class is deserialized, a generated sun.reflect.GeneratedSerializationConstructorAccessorxxx instance is put on the call stack before calling the superclass constructor, thus making it lose the privileged context in the case where the subclass itself isn't privileged.
Which is obviously silly and not true at all. When I was looking at how Sun had fixed the problem I had obtained an incorrect source for the new Calendar class and that threw me off the track. The GeneratedSerializationConstructorAccessorxxx was always on the stack, it's the means of invoking the superclass constructor. What changed is that the calling context is not so privileged anymore in the case of the Calendar.readObject(). A special AccessControlContext is created with just enough special rights to access the package sun.util.calendar, which normally isn't accessible to applet code. But if your serialized class tries to do something more (like instantiating a ClassLoader) a security exception is thrown.

Sunday, February 22, 2009

FileSystemView allows read access to the filesystem structure from an unsigned applet

(12/05/2008: Post deferred to give Sun time to fix the bug).

The bug was fixed in Java 6 update 11, released in the beginning of December 2008. Sun credited Henri Torgemane and yours truly, but I don't know Mr. Torgemane. I imagine we both reported the problem on different occasions around the same time.

Anyway, here's the original post:




I was looking at the Java applet security and file system access and seems like there's a problem in Java 6 update 6.

The class javax.swing.filechooser.FileSystemView allows listing of folder contents (to be very clear, by folder contents I mean the names of the files contained in that folder), starting from any ShellFolder (File subclass) instance.

ShellFolder instances are tricky to obtain, as access to the package is not allowed from an applet. Still, FileSystemView has two methods that return ShellFolder objects. The getRoots() and the getDefaultDirectory(). And the getFiles method returns an array of ShellFolder objects which can be used to recurse the whole filesystem. I was able to create an applet exploiting this on a Windows XP machine. The actual bug apparently was in the Win32ShellFolder2 class, which is the windows implementation for the low-level directory listing operations. The class overwrites a listFiles method and fails to ask the Security Manger if it's ok to list the files.

I originally started from an idea of an attack that involved constructing a FileDialog/JFileChooser and then having that dialog draw itself on an off-screen image. The plan was to then interpret this image an extract sensitive information from it.

Ran into some trouble with that approach. FileDialog, being an AWT component, refused to draw anything but a blank image on my image object and JFileChooser wouldn't instantiate, because the initialization tries to access the system property user.dir and the security manager won't accept that.

I proceeded to craft a subclass of JFileChooser, in which I overwrote the method that threw a security exception, calling the method of the superclass, but catching the exception, so that the init method would not fail and an instance would be created. This worked to some extent: the instance was created, a dialog window appeared, but it was empty. Nothing.

When thinking of ways to interact with the dialogs, I later thought of associating a FileFilter object with the dialog. I first tested with FileDialog, but even as I was writing the code, I read on the Javadoc that the Sun implementation doesn't take the FileFilter into consideration. I moved on to test with my crippled JFileChooser and bingo! it worked. For every file/folder in my "My Documents" folder, JFileChooser called the boolean accept(File) method of my FileFilter thus enabling me to capture the contents of that folder.

With that success, I then proceeded to try and change the folder of the JFileChooser to get access to other folders. No go. Whatever folder I set with JFileChooser.setCurrentDirectory, caused a security exception.

Not giving up so easily, I overwrote the getCurrentDirectory method to return a folder. To my surprise, that resulted in a security exception as well. That had me baffled. Why was the File object returned by the original JFileChooser working, and the one I created wasn't? I even tried to create a File with the same folder as the one that the JFileChooser returned by default. A security exception. I tried to call getParentFile() on the File object returned by the superclass. A security exception. What was going on? Then I discovered that the File instance that the getCurrentDirectory default implementation returned was actually a ShellFolder instance. ShellFolder is a subclass of File. I also discovered that the ShellFolder instance came from a class called FileSystemView that the JFileChooser uses for disk access. I found out that the FileSystemView has a getFiles(File, boolean) method which lists the contents of a folder. But calling it with a File object results in a security exception. Instantiating a ShellFolder object doesn't work, because accessing the sun.awt.shell package from an applet results in a security exception. But the FileSystemView methods getDefaultFolder and getRoots and getFiles return ShellFolder objects. In the end the solution was a lot simpler than what I was originally going for:

FileSystemView fsv = FileSystemView.getFileSystemView();

File[] roots = fsv.getRoots();
for (File root : roots) {

System.out.println(root.getPath());
}

Friday, February 13, 2009

Side-channel attack

I learned a new term the other day: Side-channel attack

While the term was new to me, the concept I was familiar with. It made me remember one of the smaller problems on Java applet security I had studied.

Untrusted applets have limited rights. There are lots of things they can't do. However, there is a ton of information about the execution environment that the applet does have access to, such as: Memory utilization, timing information, etc.

Consider, for example the method freeMemory of the Runtime class. The method can be called from an applet. Basically this method tells you how much free memory there is in the JVM. Garbage-collector and threads complicate, but basically you can use it find out how much memory a piece of code used. You'd do this by calling freeMemory before a block of code, and then immediately after the block of code, hoping the garbage collector didn't run and no other thread created objects, etc.

Consider now, a piece of privileged system code that you can execute, but it's been carefully crafted not to leak any privileged information to you.

But, in some cases, even the path that the code traverses is privileged information. You have no easy way to find out the path in a sandbox environment, but memory and timing information could be enough for a really good approximation.

Let's see a practical example:

import java.applet.Applet;
import java.util.TimeZone;

public class TZlet extends Applet {
public void start() {

for (int i=0; i < 1000; i++) {

long frees = Runtime.getRuntime().freeMemory();

TimeZone tz = TimeZone.getTimeZone("../../../../../../WINDOWS/notepad.exe");
long freee = Runtime.getRuntime().freeMemory();

System.out.println(frees-freee);
}
}

}


The getTimeZone method of the TimeZone class takes a String ID of a timezone. But, if there is no TimeZone object cached with the given ID, it reads and tries to parse a file named ID in java.home/lib/zi. So if we pass the ID "foo", it'll try to open java.home/lib/zi/foo, read the whole file into memory and then try to parse it.

From the example above, you might have guessed that it just concatenates the ID to a String which represents the path to the zi folder and does no sanity check for the ID. So we can pass ../../... until we get to the root of the drive and then put any path we please. In the case of the example: notepad.exe.

The parsing will most probably fail if you're not pointing to a zoneinfo file, so nothing useful will ever ever be returned from the method. But judging from how much memory was allocated, you can get a good approximation of the file size and test for file existence.