Summary
A couple of days ago, a Java 0day was found running like crazy in the wild. While a lot of defense bunnies where asking "WWMAD" (What will my Antivirus do?), we decide to dive into Java for the details of the vulnerability and as we expected, the unpatched vulnerabilities used in the Gondvv exploit were more than one (When we said, "dive deep into Java", we actually meant open our new Infiltrate 2013 Master Class slide deck which will include a full day of Java auditing).
The first bug was used to get a reference to sun.awt.SunToolkit class that is restricted to applets while the second bug invokes the getField public static method on SunToolkit using reflection with a trusted immediate caller bypassing a security check.
The beauty of this bug class is that it provides 100% reliability and is multiplatform. Hence this will shortly become the penetration test Swiss knife for the next couple of years (as did its older brother CVE-2008-5353).
As a final note, the bug was introduced in Java 7.0 released in July 28, 2011. While you are feeling the rush of blood going through your veins while by getting all those shell being pop, think that somewhere not far way (Probably a 10hs flight from some of the major airports in Norte Americana) was enjoying it non-stop for quite some time now.
Introduction
As the “Secure Coding Guidelines” document [1] states, it is important to understand how the permissions are checked in the Java security model. (Please readguideline 9-1).Many operations in the JDK perform permission checks before executing. Whenever a call to java.security.AccessController.checkPermission method is performed, the complete call stack that exists at that moment is analyzed.
If any of the callers in the stack do not have the required privileged an exception is raised.
When we are running code in an Applet in our browser, there is a context that has very restricted permissions.
This means that if there is any caller in the stack that is part of our applet, the permission checks will fail (unless there is a doPrivileged code block, but let's leave that out for now).
Section “9 – Access Control” in the “Secure Coding Guidelines” document [1] together with the “Java Security Architecture” document [2] will give you a complete insight on how all this works.
The Gondvv exploit
A PoC for this 0 day exploit quickly began to spread when Joshua J. Drake posted it on Twitter https://twitter.com/jduck1337/status/239875285913317376.By analyzing this implementation we can clearly see how the exploitation is done and where the vulnerabilities are really located.
The first thing we notice, is that most of the online analysis talks about one vulnerability where we saw two 2 vulnerabilities being exploited to achieve full execution on a target.
Basically the exploit is creating an java.security.AccessControlContext instance with a java.security.ProtectionDomain that has full permissions and then replace the actual AccessControlContext of a java.beans.Statement instance to be able to execute code with full privileges.
So let's take a better look at each part to understand what is happening under the hood.
In the java.beans.Statement implementation we can see that the AccessControlContext instance is a private final field and it gets its value by calling AccessController.getContext().
| 
public
   class
   Statement { 
   
   private
   static
   Object[] emptyArray
   = new
   Object[]{}; 
   
   static
   ExceptionListener defaultExceptionListener
   = new
   ExceptionListener() { 
   
       public
   void
   exceptionThrown(Exception e) { 
   
           System.err.println(e); 
   
           System.err.println("Continuing
   ..."); 
   
       } 
   
   }; 
   
   private
   final
   AccessControlContext acc
   = AccessController.getContext(); 
   
   private
   final
   Object target; 
   
   private
   final
   String methodName; 
   
   private
   final
   Object[] arguments; 
   
   ClassLoader
   loader; 
[...] 
} | 
That call to the getContext method will set the AccessControlContext to an applet context that has restrictions with a limited ProtectionDomain which of course is not privileged at all.
Back in 2010 Sami Koivu published information about a Java vulnerability (CVE-2010-0840) that built a “trusted method chain” [4].
You can see in the article that the exploitation of that vulnerability also made use of the java.beans.Statement class.
The article also explains that the fix was to add an AccessControlContext field to the Statement class setting its value to the applet context when creating an instance thus avoiding the full trusted chain.
This AccessControllContext field added in that fix is exactly what this new 0 day exploit is replacing in order to be able to execute code with full permissions.
But how can a private field be changed?
The trick here is to use the sun.awt.SunToolkit class which contains a very interesting public static method:
| 
public
   static
   Field getField(final
   Class klass, final
   String fieldName) { 
   
   return
   AccessController.doPrivileged(new
   PrivilegedAction<Field>() { 
   
       public
   Field run() { 
   
           try
   { 
   
               Field
   field = klass.getDeclaredField(fieldName); 
   
               assert
   (field != null); 
   
               field.setAccessible(true); 
   
               return
   field; 
   
           }
   catch
   (SecurityException e) { 
   
               assert
   false; 
   
           }
   catch
   (NoSuchFieldException e) { 
   
               assert
   false; 
   
           } 
   
           return
   null; 
   
       } 
   
   }); 
} | 
We can see that it is using reflection to get fields and the complete implementation is inside a doPrivileged block. This getField method can be used to get any field on a class and the good thing is that it can even retrieve private ones.
Well this is of course very useful, it's important to notice that the classes that are part of certain packages are restricted for applets and cannot be accessed or used. Such packages are:
- com.sun.deploy.* 
 
 
- com.sun.imageio.* 
 
 
- com.sun.javaws.* 
 
 
- com.sun.jnlp.* 
 
 
- com.sun.xml.internal.bind.* 
 
 
- com.sun.xml.internal.ws.* 
 
 
- sun.*
 
This means that we are not able to get a reference to the sun.awt.SunToolkit class from our applet.
But the basic thing we need to know is that calls to certain methods can potentially bypass the SecurityManager checks depending on the immediate caller's class loader.
This is explained in detail in the “Secure Coding Guidelines” document by Sun [1] in guidelines 9-8 and 9-9.
This exploit is abusing this situation taking advantage of the immediate caller to bypass security checks.
Vulnerabilities
There are 2 different zero-day vulnerabilities used in this exploit: one is used to obtain a reference to the sun.awt.SunToolkit class and the other is used to invoke the public getField method on that class.
The exploit is
making use of the java.beans.Expression which is a
java.beans.Statement subclass.
There are 2
Expression instances that are used to trigger these 2
different bugs.
When the
Expression.execute method is called it ends up calling
Statement.invokeInternal method, so let's check the
implementation:
| 
private
   Object invokeInternal() throws
   Exception { 
   
       Object
   target = getTarget(); 
   
       String
   methodName = getMethodName(); 
   
       if
   (target == null
   || methodName == null)
   { 
   
           throw
   new
   NullPointerException((target == null
   ? "target"
   : 
   
                                           "methodName")
   + " should not be null"); 
   
       } 
   
       Object[]
   arguments = getArguments(); 
   
       if
   (arguments == null)
   { 
   
           arguments
   = emptyArray; 
   
       } 
   
       //
   Class.forName() won't load classes outside 
   
       //
   of core from a class inside core. Special 
   
       //
   case this method. 
   
      
   if
   (target == Class.class
   && methodName.equals("forName"))
   { 
              return
   ClassFinder.resolveClass((String)arguments[0],
   this.loader); 
          } 
   
       Class[]
   argClasses = new
   Class[arguments.length]; 
   
       for(int
   i = 0; i < arguments.length;
   i++) { 
   
           argClasses[i]
   = (arguments[i] == null)
   ? null
   : arguments[i].getClass(); 
   
       } 
   
       AccessibleObject
   m = null; 
   
       if
   (target instanceof
   Class) { 
   
           /* 
   
           For
   class methods, simluate the effect of a meta class 
   
           by
   taking the union of the static methods of the 
   
           actual
   class, with the instance methods of "Class.class" 
   
           and
   the overloaded "newInstance" methods defined by the 
   
           constructors. 
   
           This
   way "System.class", for example, will perform both 
   
           the
   static method getProperties() and the instance method 
   
           getSuperclass()
   defined in "Class.class". 
   
           */ 
   
           if
   (methodName.equals("new"))
   { 
   
               methodName
   = "newInstance"; 
   
           } 
   
           //
   Provide a short form for array instantiation by faking an
   nary-constructor. 
   
           if
   (methodName.equals("newInstance")
   && ((Class)target).isArray()) { 
   
               Object
   result = Array.newInstance(((Class)target).getComponentType(),
   arguments.length); 
   
               for(int
   i = 0; i < arguments.length;
   i++) { 
   
                   Array.set(result,
   i, arguments[i]); 
   
               } 
   
               return
   result; 
   
           } 
   
           if
   (methodName.equals("newInstance")
   && arguments.length
   != 0) { 
   
               //
   The Character class, as of 1.4, does not have a constructor 
   
               //
   which takes a String. All of the other "wrapper" classes 
   
               //
   for Java's primitive types have a String constructor so we 
   
               //
   fake such a constructor here so that this special case can be 
   
               //
   ignored elsewhere. 
   
               if
   (target == Character.class
   && arguments.length
   == 1 && 
   
                   argClasses[0]
   == String.class)
   { 
   
                   return
   new
   Character(((String)arguments[0]).charAt(0)); 
   
               } 
   
               try
   { 
   
                   m
   = ConstructorFinder.findConstructor((Class)target,
   argClasses); 
   
               } 
   
               catch
   (NoSuchMethodException exception) { 
   
                   m
   = null; 
   
               } 
   
           } 
   
           if
   (m == null
   && target != Class.class)
   { 
                  m
   = getMethod((Class)target,
   methodName, argClasses); 
   
           } 
   
           if
   (m == null)
   { 
   
               m
   = getMethod(Class.class,
   methodName, argClasses); 
   
           } 
   
       } 
   
       else
   { 
   
           /* 
   
           This
   special casing of arrays is not necessary, but makes files 
   
           involving
   arrays much shorter and simplifies the archiving infrastrcure. 
   
           The
   Array.set() method introduces an unusual idea - that of a static
   method 
   
           changing
   the state of an instance. Normally statements with side 
   
           effects
   on objects are instance methods of the objects themselves 
   
           and
   we reinstate this rule (perhaps temporarily) by special-casing
   arrays. 
   
           */ 
   
           if
   (target.getClass().isArray() && 
   
               (methodName.equals("set")
   || methodName.equals("get")))
   { 
   
               int
   index = ((Integer)arguments[0]).intValue(); 
   
               if
   (methodName.equals("get"))
   { 
   
                   return
   Array.get(target,
   index); 
   
               } 
   
               else
   { 
   
                   Array.set(target,
   index, arguments[1]); 
   
                   return
   null; 
   
               } 
   
           } 
   
           m
   = getMethod(target.getClass(), methodName, argClasses); 
   
       } 
   
       if
   (m != null)
   { 
   
           try
   { 
   
               if
   (m instanceof
   Method) { 
   
                   return
   MethodUtil.invoke((Method)m,
   target, arguments); 
   
               } 
   
               else
   { 
   
                   return
   ((Constructor)m).newInstance(arguments); 
   
               } 
   
           } 
   
           catch
   (IllegalAccessException iae) { 
   
               throw
   new
   Exception("Statement cannot
   invoke: " + 
   
                                   methodName
   + " on "
   + target.getClass(), 
   
                                   iae); 
   
           } 
   
           catch
   (InvocationTargetException ite) { 
   
               Throwable
   te = ite.getTargetException(); 
   
               if
   (te instanceof
   Exception) { 
   
                   throw
   (Exception)te; 
   
               } 
   
               else
   { 
   
                   throw
   ite; 
   
               } 
   
           } 
   
       } 
   
       throw
   new
   NoSuchMethodException(toString()); 
    } | 
And the Statement.getMethod implementation is:
| 
static
   Method getMethod(Class<?> type, String name, Class<?>...
   args) { 
try
   { 
   
   return
   MethodFinder.findMethod(type,
   name, args); 
} 
catch
   (NoSuchMethodException exception) { 
   
   return
   null; 
} 
    } | 
Highlighted in the code you'll see the calls to com.sun.beans.finder.ClassFinder.resolveClass and com.sun.beans.finder.MethodFinder.findMethod methods.
com.sun.beans.finder.ClassFinder.findClass vulnerability
The Statement.invokeInternal method is calling com.sun.beans.finder.ClassFinder.resolveClass and if we take a look a its implementation we'll see that it ends up calling the com.sun.beans.finder.ClassFinder.findClass method:| 
public
   static
   Class<?> resolveClass(String name, ClassLoader loader)
   throws
   ClassNotFoundException { 
   
   Class<?>
   type = PrimitiveTypeMap.getType(name); 
   
   return
   (type == null)
   ? findClass(name,
   loader): type; 
} | 
| 
public
   static Class<?>
   findClass(String name) throws
   ClassNotFoundException { 
   
   try
   { 
   
       ClassLoader
   loader = Thread.currentThread().getContextClassLoader(); 
   
       if
   (loader == null)
   { 
   
           loader
   = ClassLoader.getSystemClassLoader(); 
   
       } 
   
       if
   (loader != null)
   { 
   
           return
   Class.forName(name,
   false,
   loader); 
   
       } 
   
   } catch
   (ClassNotFoundException exception) { 
   
       //
   use current class loader instead 
   
   } catch
   (SecurityException exception) { 
   
       //
   use current class loader instead 
   
   } 
   
   return
   Class.forName(name); 
} | 
This code shows that if an exception is captured, then the default is to simply call Class.forName and this is exaclty what happens here.
As it is explained in the Guideline 9-9: “Safely invoke standard APIs that perform tasks using the immediate caller's class loader instance” on the “Secure Code Guidelines” documentation [1], a call to Class.forName will use the immediate caller ClassLoader and in this case the caller is part of the JDK which is trusted thus allowing us to get any class on any package.
The caller's stack can be seen by simply debugging the applet:
MethodFinder.findMethod vulnerability
According to the “Secure Code Guidelines” document in guideline 9.8 the java.lang.Class.getMethod and java.lang.Class.getMethods only take the immediate caller into account when performing security checks.These methods can be used to get a Method reference via reflection but only “public” ones.
Even though we have a reference to the sun.awt.SunToolkit class we cannot call any of its methods directly because is part of a restricted package and a security exception will be raised.
What is needed here is a way of getting a method reference via reflection but having a “trusted” immediate caller in the stack in order to bypass security checks.
The implementation of com.sun.beans.finder.MethodFinder.findMethod is this:
| 
public
   static
   Method findMethod(Class<?> type, String name,
   Class<?>...args) throws
   NoSuchMethodException { 
    if
   (name == null)
   { 
        throw
   new
   IllegalArgumentException("Method
   name is not set 
    } 
   
   PrimitiveWrapperMap.replacePrimitivesWithWrappers(args); 
    Signature
   signature = new
   Signature(type, name, args); 
    Method
   method = CACHE.get(signature); 
    if
   (method != null)
   { 
        return
   method; 
    } 
    method
   = findAccessibleMethod(new
   MethodFinder(name, args).find(type.getMethods())); 
   
   CACHE.put(signature,
   method); 
    return
   method;} | 
The call to findAccessibleMethod ends up calling java.lang.Class.getMethods and the immediate caller in the stack is com.sun.beans.finder.MethodFinder which is trusted since is part of the JDK thus bypassing the security checks.
Once again we can see the callers stack by debugging the applet:
Affected Versions
The com.sun.beans.finder.MethodFinder and com.sun.beans.finder.ClassFinder classes are available only since JDK 7.Putting all together
So this exploit is performing the following steps:- Creates a Statement instance that will call
 System.setSecurityManager(null) method using reflection.
 
- Creates a custom AccessControlContext with full permissions.
 
- With one bug it gets a reference to the sun.awt.SunToolkit
 class that is restricted to
 applets.
 
- With the other bug it
 invokes the getField
 public static method on sun.awt.SunToolkit
 using reflection with a trusted immediate caller that bypasses the
 security checks.
 
- With the getField
 method it is getting a reference to Statement.acc
 private field and  setting its value to the custom
 AccessControlContext instance previously created.
 
- Finally it executes the Statement that will disable the Security Manager bypassing all security checks because it has full permissions set in its AccessControlContext.
Author
Esteban Guillardoy
esteban@immunityinc.com
twitter: @sagar38
References
[1] - Secure Coding Guidelines for the Java Programming Language, Version 4.0 - http://www.oracle.com/technetwork/java/seccodeguide-139067.html[2] - Java SE 7 Security Architecture - http://docs.oracle.com/javase/7/docs/technotes/guides/security/spec/security-specTOC.fm.html
[3] - Java SE 7 Security Documents - http://docs.oracle.com/javase/7/docs/technotes/guides/security/
[4] - Sami Koivu Blog - Java Trusted Method Chaining (CVE-2010-0840/ZDI-10-056) - http://slightlyrandombrokenthoughts.blogspot.com.ar/2010/04/java-trusted-method-chaining-cve-2010.html


 
7 comments:
Well done finding the second vulnerability. To be honest, I stopped when finding the first one too, without thinking about how the method is actually invoked later.
BTW CVE-2012-4681 will coexist next to CVE-2012-1723, which is able to exploit any versions from 1.4 to 7 published last year or earlier, not only Java 7, and especially every publicly available 1.4 or 5 version ever published :)
Interesting the CVE speaks only about 1.7 having the vuln "and possibly others" have you tested 1.4-1.7?
I was wondering how is it possible to modify Statement.acc even though it has modifier final. It seems that the field.setAccessible(true) call in getField is enough to allow the modification of a final field.
is emet 3.5 can do something with this security flaw ?
i can also get sun.xxx like this:
"
Object t[] = new Object[1];
t[0]= Class.forName(paramString);
return (Class)t[0];
"
Looks like the fix in 1.7_07 was to add explicit calls to ReflectUtil.checkPackageAccess() at the beginning of the two com.sun.beans.finder.ClassFinder findClass() variants.
Post a Comment