0%

fastjson1.2.22-1.2.24反序列化流程

前言

接上一篇进行1.2.22-.1.2.24 fastjson源码漏洞的分析

反序列化流程

1
2
3
4
5
6
7
8
9
10
11
public class Ser {
public static void main(String[] args) throws IOException {
Person person = new Person();
person.setName("harry");
person.setAge(22);
person.setGender("male");
String jsonstring = JSON.toJSONString(person, SerializerFeature.WriteClassName);
//反序列化入口parseObject
System.out.println(JSON.parseObject(jsonstring));
}
}

反序列化入口,断点更进.

然后来到parseObject函数内部,位于JSON.class line 201

继续更进parseObject函数的parse函数 来到了line 128

然后跟进DefaultJsonParser函数进入DefultJSONParser.class

触发了上面这个重载,来到下图line 175,函数的作用对输入的字符串第一个字符仅那个了判断并标记为常量值以判断类型

继续放行,这里是判断刚刚传导出来的类型即{为12

继续放行来到了line 322这个if块,这里是得到我们传入类的类名

step over来到

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
//载入类   
public static Class<?> loadClass(String className, ClassLoader classLoader) {
//判断传入类
if (className == null || className.length() == 0) {
return null;
}

Class<?> clazz = mappings.get(className);

if (clazz != null) {
return clazz;
}

if (className.charAt(0) == '[') {
Class<?> componentType = loadClass(className.substring(1), classLoader);
return Array.newInstance(componentType, 0).getClass();
}

if (className.startsWith("L") && className.endsWith(";")) {
String newClassName = className.substring(1, className.length() - 1);
return loadClass(newClassName, classLoader);
}

try {
if (classLoader != null) {
clazz = classLoader.loadClass(className);
mappings.put(className, clazz);

return clazz;
}
} catch (Throwable e) {
e.printStackTrace();
// skip
}

try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
//如果类不是内置类型,那就载入用户传入的类
if (contextClassLoader != null) {
clazz = contextClassLoader.loadClass(className);

mappings.put(className, clazz);

return clazz;
}
} catch (Throwable e) {
// skip
}

try {
clazz = Class.forName(className);
mappings.put(className, clazz);

return clazz;
} catch (Throwable e) {
// skip
}

return clazz;
}

载入前后的mappings的变化.自定义的类被载入进来了

step in 这个getDeserializer函数,跳入ParserConfig.class有一个黑名单过滤,黑名单中只对java.lang.Thread进行了限制,其他类均可以载入.

至此java.lang.Runtime被正常载入,就可以通过这个类进行RCE,在程序调用反序列化的函数parseObject的时候就会执行