Wednesday, December 03, 2008

Calendar bug

Java 6 Update 11 fixes "calendar security bug" among others.

Altough some minor adjustments were made to the Calendar class, the actual fix deals with how deserialization calls non-serializable superclass constructor. But I like to call it the Calendar bug, anyway, because in my original evaluation of the problem I put the blame on the java.util.Calendar class.

The problem, which is present in Java 6 Update 10 and earlier (and in the corresponding Java 5 and Java 1.4.2 releases), goes something like this:

java.util.Calendar is a serializable class. Presumably due to reverse compatibility, its serialization logic is non-trivial. One of the non-trivial things that it does, is that the readObject method (which is used for customizing object deserialization) calls ObjectInputStream.readObject() inside a doPrivileged block to deserialize a ZoneInfo object which might or might not be present.

Something like this:
// If there's a ZoneInfo object, use it for zone.
try {
ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return input.readObject();
}
});
if (zi != null) {
zone = zi;
}
} catch (Exception e) {
}


doPrivileged blocks are used when the caller of trusted code doesn't necessarily have the privileges to execute some operation. In this specific case, the ZoneInfo object being deserialized resides in the sun.util.calendar package and applet code normally doesn't have access to this package (or any package which starts with "sun.").

Without the doPrivileged block, if an unsigned applet were to try to deserialize a Calendar object, it would raise a SecurityException. With doPrivileged, the code executes fine even when the caller (unsigned applet code) doesn't have the privileges. There is an old bug related to deserializing calendar objects and the doPrivileged block was presumably the fix.

The problem is that there is absolutely no guarantee that the stream being read contains a ZoneInfo object. It might contain, for example, a serializable ClassLoader subclass. One would have to manouver a bit to create such a stream, but with basic knowledge of the Java serialization protocol, this is a relatively trivial task.

So what happens if there should to be a Serializable ClassLoader subclass in the stream in the place of the ZoneInfo object? What's the big deal?

The input.readObject() method would execute just fine, because it has no knowledge of what type of an object it is supposed to deserialize. It reads the stream, gets the details of the next object in the stream, instantiates the object (without calling the constructor) and returns the object.

At this point the Calendar code tries to do a cast of the object to the ZoneInfo type and this will cause a ClassCastException, as the types aren't compatible. But the object was deserialized just fine. The implication of this is that applet code can deserialize objects in a privileged context, just by constructing an input stream (ByteArrayInputStream, for example) which contains a special serialized Calendar object which contains some other object instead of a ZoneInfo.

You might think that the reference to the newly created object is forever lost, only to be collected by the garbage collector later on. However, it is possible to implement a readObject method in the serializable class which stores the reference to the created object in some static context.

So what?

Here's where the ClassLoader comes into play. java.lang.ClassLoader is not Serializable and thus can't be serialized. But it is a non-final class, so it can be extended.

Subclasses of non-serializable classes can be serializable just by implementing the java.io.Serializable interface. When the object is deserialized, the JVM first calls the constructor of the non-serializable class, and then it deserializes the fields of the serializable subclass. The fancy part is that there will be no subclass code on the stack when the constructor of the non-serializable class is called (or rather, this was true until update 11). Thus, if the deserialization happens in a privileged context, the constructor also gets called in a privileged context.

Why is this relevant?

Because calling a ClassLoader constructor requires special privileges. Privileges that an unsigned applet normally doesn't have. So this way an applet could (past tense, because of the fix in update 11) obtain it's very own ClassLoader. If you have access to your own ClassLoader subclass, you can load new classes with any privileges. You can load a class which has the privileges to do anything that the user running the browser running the applet can do, including, but not limited to, removing files, opening connections and executing external programs.

So how did Sun fix the bug?

Well, first of all, they left the doPrivileged block in the Calendar class. I'm not a 100% percent sure that was a correct decision, but more about that later on.

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.

I had to correct myself on this one.

Sunday, May 11, 2008

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());
}

Saturday, May 10, 2008

Security is hard

Security is hard.

When you're trying to build something secure, you have to consider everything.

When you're breaking the security, you just have to think of one thing that the other guy didn't think of. Not to mention the person creating security is normally vastly outnumbered.

I like security. I like locks (designing locks and dreaming up ways to defeat them). I like security protocols (analyzing them anyway, following them can be a pain). I like security related algorithms (encryption, one-way hashing, etc). I like security in software development.

These days I've been revisiting the security of Java's sandbox while running in applets. It's wildly intriguing, because of the complexity involved. Even a simple login screen can be complicated to get just right, in terms of security. And the applet sandbox is a whole different beast. The applets need to be able to do almost anything.. and then there are a few, handful of things that the applet absolutely must not be able to do. Add to the mix Java's system of access modifiers, inheritance, threads, serialization, bytecode, etc. It's a complicated thing. I can't believe they've got it 100% right. Can't believe it. It doesn't seem probable. So often, when I have spare time I go about looking at the Java core code, doing tests, trying to be creative.