Sunday, February 06, 2011

Java JFileChooser Programmatic Manipulation Vulnerability

Java GUI Manipulation Vulnerability

This bug reaches the severity threshold where ideally I wouldn't talk about it until a fix has been issued, but as the Facebook relationship status would put it: It's complicated. It doesn't qualify for ZDI because I already notified Sun by myself in 2008 about various vulnerabilities, first via their bug tracking (I didn't know any better) system and later on via e-mail to their security address, which resulted in the famous Calendar Serialization issue getting fixed. This JFileChooser issue just never got fixed. To be clear: after 2008, they never got back to me and I didn't harass them to fix it.

JFileChooser and FormView allow unsigned applets to read file-system structure (file/folder names), renaming files and moving files

Affected Operating Systems (at least): Windows XP, Windows 7
Affected Java Versions (at least): Java 6 update 23

Details

javax.swing.JFileChooser is a Java Swing component that allows the user to choose a file on the local filesystem. It cannot normally be used on an applet, because the initialization tries to read the user.home system property which is not permitted. So, if you try to do a "new JFileChooser()" you get a SecurityException and you won't get a handle to any object. And if you use the finalizer attack, you get an instance that isn't really functional.

This is where javax.swing.text.html.FormView comes in. It has a createComponent() method, which - with the right setup - creates a bunch of objects, one of them being a button, whose ActionListener creates a JFileChooser. That ActionListener can be extracted and then javax.swing.Timer can be used to execute the ActionListener.

Timer is used for executing ActionListeners in a timed fashion, and due to that nature, it executes them on a separate Thread which has no user code on the stack. In other words, it executes ActionListeners in a privileged context. Thus, the JFileChooser constructor runs fine.

So, a JFileChooser is created and displayed on the screen and the user can interact with it, but that doesn't do us much good, since we don't even have a reference to the JFileChooser. That's where Window.getWindows() comes in. It returns an array of all Windows accessible to the Applet, the JFileChooser being one of them. This way we get a reference to our JFileChooser instance.

What can we do with a JFileChooser? It only has methods for getting the selected file(s), once the user has made his selection and that's no good.

We can, however, define a FileFilter for the JFileChooser and that's interesting, because it'll receive File objects for each file in the current directory (so it can tell JFileChooser whether or not to display the file in question). This happens for the initial folder and also for any other folders, should the user navigate elsewhere with the JFileChooser. But since the user is not expecting to see a file chooser dialog, not a lot of navigation is to be expected.

There's an even better method to interact with the JFileChooser. Java AWT/Swing superclass java.awt.Component provides the method getComponents() which returns an array of child components. This way if you start at the top, in this case the JFileChooser, you can navigate to all the child components of the GUI, the buttons, the comboboxes, everything. Combine that with the fact that javax.swing.Timer can be used to execute the ActionListeners of any of these GUI components and you can pretty much simulate any user action on the JFileChooser.

So, we can view the file system structure of the machine running the applet. The JFileChooser has two additional interesting functionalities, which are the following: It can create empty folders and it can rename files and folders. Also, renaming files to "../newname" moves them toward the root in the filesystem and renaming files to "folder/newname" moves them into the folder. This means we can also move the files and folders.

Depending on other configuration like operating system, etc, this might be used for delayed Remote Code Execution. For example, a .jar might be moved from the Java Cache into the Java extension folder which has higher permissions. Or imagine an executable posing as an image, which gets renamed, then moved to a system folder.


Original bug report (2008)

Bug ID: 6764977
Review ID: 1379484

Date Created: Sun Oct 26 19:59:11 MST 2008
Type: bug
Customer Name: Sami Koivu
Customer Email: sami.koivu@gmail.com
SDN ID: sami.koivu@gmail.com
status: Waiting
Category: java
Subcategory: classes_swing
Company: IT7 Solution Technology
release: 6u10
hardware: x86
OSversion: win_xp
priority: 4
Synopsis: FormView allows untrusted applet read access to the filesystem structure
Description:
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
javax.swing.text.html.FormView allows an untrusted applet to instantiate a JFileChooser in the event thread without untrusted applet code on the stack thus escaping intervention of a SecurityManager.

FormView can be subclassed and instantiated in such a way that the createComponent method returns a Component which contains a button whose ActionListener is the inner class BrowseFileAction.

This BrowseFileAction can then be extracted and executed via javax.swing.Timer on the event thread. The important thing to notice is that there will be no applet code on the stack and thus the applet security manager will allow the operation.

A JFileChooser dialog is opened. A reference to this dialog can be obtained via Window.getWindows(). Through this reference, using the AWt/Swing component structure (basically calling getComponent() to access the children of each GUI component) the filenames in the current (default) directory can be obtained. The dialog can also be manipulated in order to change the current browsing directory in the same fashion. Thus the whole directory structure on the system of the user running the applet could be obtained.

Unconfirmed, but it seems probable it would be possible to stimulate the file rename functionality as well, allowing an untrusted applet to rename any file on the system of the user running the applet.

It should also be noted that the dialog can be made invisible as soon as a reference to it is obtained (causing the dialog to only briefly appear on the screen).

I have a raw example of this available if absolutely necessary, but it is rather verbose and not very readable.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Stimulate FormView.BrowseFileAction to show a JFileChooser dialog.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either the action object is somehow made inaccessible or security manager will perceive somehow that there is applet code behind this operation disallowing the operation.
ACTUAL -
A JFileChooser object is instantiated and displayed on the screen and can be manipulated in a manner that will at the very least invade the privacy of the web surfer.

REPRODUCIBILITY :
This bug can be reproduced always.


Evaluation from Sun Microsystems (2008)
It's perfectly correct to create JFileChooser under SecurityManager,
and in this case user will be able to browse the file structure,
it is *the code* who will not be able to do anything with those files

The bug's description doesn't show any way how an untrusted applet can read
the filesystem structure, we need more information
Posted Date : 2008-11-10 15:06:03.0


My response to evaluation (2008)
Ok, maybe the initial bug description was too superficial.

Here's a more detailed one. I'll do a bullet list and if necessary I can later be more specific on any single item.

* An instance of FormView's private inner class BrowseFileAction can be extracted.

* Said instance can be executed with javax.swing.Timer. The Timer class is used to executed ActionListeners in a timed fashion. When the Timer class is used to execute core ActionListeners only trusted code will be on stack and the security manager allows everything. BrowseFileAction is not the only problem. (BasicFileChooserUI.NewFolderAction can be used to create folders and there must be other vulnerable ActionListeners in the rt.jar, as well).

* When executed, BrowseFileAction opens a JFileChooser dialog. This alone might be acceptable or not. Keep reading.

* The java.awt.Window class has a method called getWindows() which according to the javadoc: "Returns an array of all {@code Window}s, both owned and ownerless, created by this application."

* Said method can be used to obtain a reference to the window which contains the JFileChooser instance. This goes something like:
JDialog dlg = (JDialog) Window.getWindows( ... );
JRootPane root = dlg.getRootPane();
JLayeredPane layered = (JLayeredPane) root.getComponent(1);
JPanel panel = (JPanel) layered.getComponent(0);
JFileChooser fc = (JFileChooser) panel.getComponent(0);

* (if you set your custom FileFilter on this instance, it will call your FileFilter's accept method once which each file of the current directory *the code* will be receiving this information)

* You can use the Container.getComponent(int) method on the JFileChooser to obtain all the direct and subcomponents of the JFileChooser. That is, the JComboBox subclass which controls the current directory and the sun.swing.FilePane object which contains a JList which contains the files in the current directory. You would go about it like this (YMMV):

JPanel panel = (JPanel) fc.getComponent(0);
JComboBox combo = (JComboBox) panel.getComponent(2);

* You can manipulate the JComboBox to change the current directory. You might, for instance, obtain the actionlisteners of the combobox, remove them from the combobox, set the seleted index of the combobox to a different value and then user javax.swing.Timer to execute the actionlisteners to update the JFileChooser.

* You can get the action for editing a filename from the FilePane in the same way described above. You can then execute the EditActionListener using javax.swing.Timer. This will cause the JFileChooser to display a JTextField for editing the filename. A reference to this JTextField can be obtained as described above (Container.getComponent(int)). The value of the text can be change by *the code* (setText(String) and another action can be invoked via javax.swing.Timer to tell JFileChooser that editing has terminated which will cause it to rename the file. Or move the file, if the file is renamed to "../filename" or "folder/filename".


Example - Caution, running this will rename and move a file on your system

(This works on Windows XP/Windows 7, file renaming doesn't work on Linux though it might be possible with extra effort)

It pops up a JFileChooser, goes to the first folder in the Location combobox, selects the 6th file and prefixes the name with "new" and moves it to the parent directory.

EDITED: This link is just the source code of the example. Safe to click. In order to run it you would need to compile it and create a page with an applet definition.

http://pastebin.com/mTCztGbQ

10 comments:

Anonymous said...

The Problem is neither JFileChooser nor FormView, it's the Timer which allows calling code in a privileged security context instead of the context of the Timer's creator.

There are other exploits imaginable. For example, you could bind the Paste-Action of Swing's TransferHandler to the Timer to read the current Clipboard contents into a TextPane.

Anonymous said...

It doesn't work for me because of the following line:
JTextField f = (JTextField) list.getComponent(1);


getting the exception:

java.lang.ArrayIndexOutOfBoundsException: No such child: 1
at java.awt.Container.getComponent(Unknown Source)
at Example.demo(Example.java:104)
at Example.start(Example.java:22)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Sami Koivu said...

If you wanna go down that path, I'll just say, no, the Timer isn't the problem, the problem is that the Java security is fundamentally broken. :)

But yes, Timer executing stuff without capturing the context of the creator of the Timer is one of the many problems, for sure. However, fixing that isn't very trivial. The event thread is privileged, too. If you have an ActionListener you want executed, you don't have to use Timer, it's just the cleanest way to do it.

Sami Koivu said...

Anonymous #2: What's your OS, Java version? That piece of code makes a lot of assumptions (about filesystem structure, etc), I made it basically just to show how one could go about attacking JFileChooser. I have no doubt that it will not work on all, maybe not even most setups, without modification.

Michael said...

ok i had java 1.6.22 installed :O
after an update to 23 it worked

Anonymous said...

Java is full of old bugs. For example, there still is no munmap() euqivalent (but there is mmap(), you just have to hope the garbage collector will munmap it sometime); circles are drawn as diamonds with certain zoom settings (e.g. with Batik)

But given that Oracle lost many of the Java gods, I'm not very confident that things will improve. On contrary, I belive that Oracle will do just enough to not lose their paying customers.

Anonymous said...

It seems that with Java 1.6.0_24 (released today) this vulnerability has been fixed.

Anonymous said...

is this now fixed in java 1.6.0_24 or is it not?

Sami Koivu said...

Anonymous: There some indication that it may have been fixed, but I haven't been able to verify (out of time)

Sami Koivu said...

OK, finally had the time to verify that this issue has indeed been fixed. Oracle improved the security of the Timer and event thread and fixed this issue among others.