Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

[SE-2012-01] More details on Issue 32 and Oracle's 'fix' for it
From: Security Explorations <contact () security-explorations com>
Date: Sun, 13 Jan 2013 13:01:37 +0100


Hello All,

We would like to share a few more words regarding the recent Java
0-day [1] and its relation to our Issue 32 [2]. This is primarily
done in a response to Immunity Inc. [3] write-up [4] containing
the analysis we cannot agree with.

We stand in whole by the claims that we've made recently [5]. While
the post sent to the Bugtraq / Full Disclosure mailing lists was
a really quick work and it does contain some minor errors, our
primary point behind the analysis made has not changed a bit.
The 0-day attack code (in the form found in the wild) would not
be possible if Issue 32 had been correctly resolved by Oracle in
Oct 2012 Java SE CPU.

In order to defend our claims, we would like to provide you with
more detailed information regarding Issue 32 and the fix for it.

As some of you remember Issue 32 was found on Aug 30, 2012, hours
after Oracle released its out-of-band patch for the 0-day attack
exploited in the wild [6]. We have published information about
Issue 32 as part of our SE-2012-01 project disclosure on Nov 16
2012.

Our technical paper [7] states that at the core of Issue 32 is a
call to the native invokeExact method of the MethodHandle class
used from a wrapper invokeWithArguments (page 36). To illustrate
this we provided a decompiled source code of the vulnerable method,
which is also illustrated below:

public transient Object invokeWithArguments(Object aobj[])
      throws Throwable {

      int i = aobj != null ? aobj.length : 0;

      MethodType methodtype = type();

      if (methodtype.parameterCount() != i || isVarargsCollector()) {
          return 
asType(MethodType.genericMethodType(i)).invokeWithArguments(aobj);
      } else {
          MethodHandle methodhandle = 
methodtype.invokers().varargsInvoker();
          return methodhandle.invokeExact(this, aobj);
      }

The above method contains a vulnerability because it allows to
call arbitrary methods with a system class (from NULL Class Loader
namespace) set as a caller class (as seen on the call stack by
stack walking routines such as Reflection.getCallerClass one).
Such a condition is dangerous because there are many locations in
Java SE code that conduct security checks based on the caller of
the given method. The class that would be visible to the security
checks would be the one declaring invokeWithArguments method. For
calls made through invokeWithArguments method this would be the
java.lang.invoke.MethodHandle class.

On page 37 of our paper we state that the call looked similar to
the problem related to Core Reflection API and the invoke method
in particular (arbitrary invoke call done from a system class with
user provided arguments).

Finally, on page 44 we summarize Issue 32 and provide the following
description for it:
  origin: java.lang.invoke.MethodHandle
  cause:  the possibility to call invokeExact from a system wrapper
          method
  impact: bypass of security checks based on the immediate caller
  type:   complete security bypass vulnerability

That was rather humble description, but should be sufficient taking
into account our paper describing the nature of Reflection API based
issues (the reliance on the caller class for all various sorts of
security checks).

In order to complete the picture and feeling that information provided
so far is not enough, we decided to publish our original report that
was sent to Oracle and that described the cause of Issue 32. We have
made it available for download from here:

http://www.security-explorations.com/materials/SE-2012-01-ORACLE-5.pdf

This report states the following among other things:

"The new weakness has its origin in java.lang.invoke.MethodHandle
class. It allows to invoke arbitrary (both static and virtual)
methods with an immediate caller originating in a null class
loader namespace. The problem stems from the fact that
invokeWithArguments method of MethodHandle class can be used
as a wrapper method for the actual invokeExact method invocation.
Such a wrapper call leads to the additional stack frame of a
system class being asserted into the call stack, which allows
to bypass security checks based on the immediate caller of a given
security sensitive method. Examples, of such methods include
Reflection API based ones, but also getUnsafe of sun.misc.Unsafe
class.

The above should serve as a better summary of Issue 32.

Now, let us go into the fix that was implemented by Oracle and
that tried to address Issue 32.

Oracle decided to detect attempts to acquire MethoHandle objects
pointing to security sensitive methods that conduct security
checks based on the caller class. New maybeBindCaller method was
introduced to the code of MethodHandles.Lookup class. This method
returns original instance of the target MethodHandle to the caller
of a corresponding new Reflection API call (findVirtual, findStatic,
etc.) if either the lookup object is fully trusted or the target
method is not sensitive. The check for method sensitiveness is
conducted by isCallerSensitive method of MethodHandleNatives class.
This is illustrated below:

private MethodHandle maybeBindCaller(MemberName membername, MethodHandle 
methodhandle)
     throws IllegalAccessException {

     if (allowedModes == -1 || 
!MethodHandleNatives.isCallerSensitive(membername))
         return methodhandle;

     Class class1 = lookupClass;

     if ((allowedModes & 2) == 0) class1 = null;

     MethodHandle methodhandle1 = 
MethodHandleImpl.bindCaller(methodhandle, class1);
     methodhandle1 = fixVarargs(methodhandle1, methodhandle);
     return methodhandle1;
}

A look at the isCallerSensitive method reveals that sensitive
caller corresponds to all methods that rely directly / indirectly
on Reflection.getCallerClass method. This is the reason for many
core Reflection API methods to be treated as sensitive. But, this
is not all as there are many more methods in Java SE that rely on
a caller (class or class loader) prior to making certain security
decisions. This is the reason for paving the way into the blacklist
for the following methods (among others) as well:
- doPrivileged method of AccessController class
- invoke method of java.lang.reflect.Method class
- get, getBoolean, getByte, getChar, getShort, getInt, getLong,
   getFloat, getDouble, set, setBoolean, setByte, setChar, setShort,
   setInt, setLong, setFloat and setDouble methods of 
java.lang.reflect.Field
   class
- getUnsafe method of sun.misc.Unsafe class
- ...

Among sensitive methods there is only one coming from new Reflection
API. This is the lookup method of MethodHandles.Lookup class.

For sensitive methods, instead of returnig DirectMethodHandle
object, an instance of AdapterMethodHandle is returned as a result
of a call to findVirtual, findStatic, etc. This is the handle that
is "bound" to the caller and is used for all security sensitive
methods detected by isCallerSensitive call.

When such a bound AdapterMethodHandle is used as a base for the
invokeWithArguments method call, the call to invokeExact is done
through a trampoline caller class (MethodHandleImpl.BindCaller.T
class to be precise) defined in a separate Class Loader namespace.
This is the usual technique for mitigating the risks related to
insecure Reflection API implementation. Separate stack frame coming
from a non-null, unprivileged Class Loader namespace is injected
into the call stack prior to the call to the target method. As a
result, all security checks are conducted with respect to such an
unprivileged caller class, not the system caller.

So, what's the problem with Oracle patch for Issue 32 ? This patch
missed findVirtual, findStatic and other new Reflection API methods
in its detection process for security sensitive methods that might
be invoked through invokeWithArguments. The lookup method of the
MethodHandles.Lookup class was the only method of new Reflection
API which was blacklisted. It's implementation is provided below:

     public static Lookup lookup()
     {
         return new Lookup();
     }

A look at the constructor of the Lookup class reveals that it
indeed relies on the caller for security reasons among other
things:

         Lookup()
         {
             this(getCallerClassAtEntryPoint(false), 15);
             checkUnprivilegedlookupClass(lookupClass);
         }


But, getCallerClassAtEntryPoint method is also invoked by the base
security check method used by other new Reflection API methods. This
is accomplished indirectly by the means of checkSecurityManager call:

void checkSecurityManager(Class class1, MemberName membername) {
     SecurityManager securitymanager = System.getSecurityManager();
     if (securitymanager == null) return;

     if (allowedModes == -1) return;

     securitymanager.checkMemberAccess(class1, 0);

     Class class2 = (allowedModes & 2) == 0 ?
                       getCallerClassAtEntryPoint(true) : lookupClass;

     if (!VerifyAccess.classLoaderIsAncestor(lookupClass, class1) ||
        class2 != lookupClass && 
!VerifyAccess.classLoaderIsAncestor(class2, class1))
 
securitymanager.checkPackageAccess(VerifyAccess.getPackageName(class1));

     if (membername.isPublic()) return;

     Class class3 = membername.getDeclaringClass();

     securitymanager.checkMemberAccess(class3, 1);

     if (class3 != class1)
 
securitymanager.checkPackageAccess(VerifyAccess.getPackageName(class3));
}

The above security check makes sure that the caller of findVirtual,
findStatic, etc. methods comes from same Class Loader namespace as
the target class upon which a lookup for method / constructor is
conducted and that it is no different than the namespace of the
lookupClass object.

The reliance on the caller class for security reasons should result
in blacklisting all new Reflection API calls that make use of the
checkSecurityManager method. But, this did not happen.

New Reflection API methods that were missed from being put into the
blacklist are the following methods of MethodHandles.Lookup class:
- findStatic
- findVirtual
- findConstructor
- findSpecial
- findGetter
- findSetter
- findStaticGetter
- findStaticSetter
- bind

With the background provided above, we are ready to discuss the 0-day
and its correspondence to Security Explorations' Issue 32.

As it was indicated in our previous post, the 0-day code makes use of
two vulnerabilities. The MBeanInstantiator issue used for obtaining
references to restricted classes is a completely new vulnerability.

The other issue makes use of the invokeWithArguments of MethoHandle
class. This call is used in order to trick the called method (such
as findVirtual and findConstructor in particular) that the caller
is trusted. And this is actually the core cause of Issue 32.

The bypassing of the security check in checkSecurityManager method
happens due to the following:
1) callerClass is a system class from NULL Class Loader namespace
    (java.lang.invoke.MethodHandle class asserted into the call stack
    by invokeWithArguments method, the target MethodHandle is not
    bound)
2) lookupClass is a public lookup based on java.lang.Object, it is
    naturally coming from the same Class Loader namespace as any other
    system class (such as a restricted class for which a given find
    call was invoked)
3) callerClass is from the same Class Loader namespace as as any
    othe system class (such as a restricted class for which a given find
    call was invoked)

The key bug used by the recent Java 0-day code relies on exactly the
same thing as Issue 32 that we reported to Oracle on Aug 31, 2012.
It exploits the fact that several new Reflection API calls were not
put into the blacklist even though they rely on the caller class for
security checks (indirect reliance on Reflection.getCallerClass). If
these methods were put into the MethodHandleNatives blacklist,
callerClass would be the dummy class injected into the call stack as
a result of MethodHandle binding operation. This would further trigger
the security check inside checkSecurityManager method (a call to
checkPackageAccess of Security Manager). This call would result in
a security exception being thrown (access denied to restricted class).

The quick experiment confirms all of the above. We added the following
code to isCallerSensitive method in order to protect the two find calls
used in 0-day code from being abused by the invokeWithVirtual method:

         case "findConstructor":
         case "findVirtual":
           return defc == java.lang.invoke.MethodHandles.Lookup.class;

The quick patch was applied to the MethodHandleNatives.java file that
is available inside the jdk1.7.0_10 installation directory (src.zip
archive with source code).

The patched code was compiled into the following two class files:
- MethodHandleNatives.class
- MethodHandleNatives$Constants.class

They had been put into rt.jar file of the JRE lib directory replacing
the original classes.

We have later conducted an attempt to run the following code fragment
being part of the 0-day code spotted in the wild:

      Class 
lookup_class=Class.forName("java.lang.invoke.MethodHandles$Lookup");
      MethodHandle 
findconstructor_mh=lookup.findVirtual(lookup_class,"findConstructor",desc);

      System.out.println("findconstructor_mh: 
"+findconstructor_mh.getClass());

      desc=MethodType.methodType(Void.TYPE);

      MethodHandle 
constructor_mh=(MethodHandle)findconstructor_mh.invokeWithArguments(lookup,context_class,desc);

On JRE version 1.7.0_10-b18 this produced the following result:

Security manager = sun.plugin2.applet.AWTAppletSecurityManager () 12d96f
findconstructor_mh: class java.lang.invoke.AdapterMethodHandle
java.security.AccessControlException: access denied 
("java.lang.RuntimePermission" 
"accessClassInPackage.sun.org.mozilla.javascript.internal")
        at 
java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
        at 
java.security.AccessController.checkPermission(AccessController.java:560)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1529)
        at 
sun.plugin2.applet.SecurityManagerHelper.checkPackageAccessHelper(Unknown Source)
        at 
sun.plugin2.applet.AWTAppletSecurityManager.checkPackageAccess(Unknown 
Source)
        at 
java.lang.invoke.MethodHandles$Lookup.checkSecurityManager(MethodHandles.java:1125)
        at 
java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:685)
        at 
java.lang.invoke.MethodHandleImpl$BindCaller$T/8717058.invoke_V(MethodHandleImpl.java:1422)
        at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:566)
        at BlackBox.<init>(BlackBox.java:132)

The above indicates a couple of things:
- obtained findconstructor_mh MethodHandle is an instance of the class
   AdapterMethodHandle, this indicated that the handle is "bound" as
   potentially vulnerable to abuse by invokeWithArguments method call
- there is an additional class on the stack frame put immediately before
   the target findConstructor call, this is MethodHandleImpl$BindCaller$T
   class (dummy trampline class separating trusted caller from a security
   sensitive method),
- checkSecurityManager routine now detects that the caller class is not
   compatible with both the lookup and target classes (their CL namespaces),
   thus a call to checkPackageAccess is made,
- Issue 32 and exploit code are both blocked.

In case of no patch, same code fragment above produces the following
output:

Security manager = sun.plugin2.applet.AWTAppletSecurityManager () 1be9101
findconstructor_mh: class java.lang.invoke.DirectMethodHandle
Security manager = null

This output indicated the lack of protection for findconstructor_mh,
which makes it vulnerable to the abuse abuse by invokeWithArguments
method call (a trusted MethodHandle class is seen as a caller by
the security check routine).

We hope the above analysis clears all doubts regarding our claims and
the correspondence of Issue 32 to the recent 0-day. We also hope that
the subtle technical pecularities regarding Issue 32 and Reflection
API are more clear now to all interested parties.

Thank you.

Best Regards
Adam Gowdiak

---------------------------------------------
Security Explorations
http://www.security-explorations.com
"We bring security research to the new level"
---------------------------------------------

References:

[1] Malware don't need Coffee: 0 day 1.7u10 spotted in the Wild - 
Disable Java Plugin NOW !
 
http://malware.dontneedcoffee.com/2013/01/0-day-17u10-spotted-in-while-disable.html
[2] [SE-2012-01] New security issue affecting Java SE 7 Update 7
     http://seclists.org/fulldisclosure/2012/Aug/388
[3] Immunity Inc
     http://www.immunityinc.com/
[4] Esteban Guillardoy "Java MBeanInstantiator.findClass 0Day Analysis"
 
https://partners.immunityinc.com/idocs/Java%20MBeanInstantiator.findClass%200day%20Analysis.pdf
[5] [SE-2012-01] 'Fix' for Issue 32 exploited by new Java 0-day code
     http://seclists.org/fulldisclosure/2013/Jan/66
[6] Zero-Day Season is Not Over Yet
 
http://blog.fireeye.com/research/2012/08/zero-day-season-is-not-over-yet.html#more
[7] "Security Vulnerabilities in Java SE", technical report
     http://www.security-explorations.com/materials/se-2012-01-report.pdf

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/


  By Date           By Thread  

Current thread:
  • [SE-2012-01] More details on Issue 32 and Oracle's 'fix' for it Security Explorations (Jan 14)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]
AlienVault