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 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) {


No comments: