前言
接上一篇进行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); 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(); }
try { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (contextClassLoader != null) { clazz = contextClassLoader.loadClass(className); mappings.put(className, clazz);
return clazz; } } catch (Throwable e) { }
try { clazz = Class.forName(className); mappings.put(className, clazz);
return clazz; } catch (Throwable e) { }
return clazz; }
|
载入前后的mappings的变化.自定义的类被载入进来了
step in 这个getDeserializer函数,跳入ParserConfig.class
有一个黑名单过滤,黑名单中只对java.lang.Thread
进行了限制,其他类均可以载入.
至此java.lang.Runtime
被正常载入,就可以通过这个类进行RCE,在程序调用反序列化的函数parseObject
的时候就会执行