博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
FastJson反序列化漏洞利用的三个细节 - TemplatesImpl的利用链
阅读量:6293 次
发布时间:2019-06-22

本文共 3731 字,大约阅读时间需要 12 分钟。

0. 前言

记录在FastJson反序列化RCE漏洞分析和利用时的一些细节问题。

1. TemplatesImpl的利用链

关于 parse 和 parseObject

FastJson中的 parse() 和 parseObject()方法都可以用来将JSON字符串反序列化成Java对象,parseObject() 本质上也是调用 parse() 进行反序列化的。但是 parseObject() 会额外的将Java对象转为 JSONObject对象,即 JSON.toJSON()。所以进行反序列化时的细节区别在于,parse() 会识别并调用目标类的 setter 方法及某些特定条件的 getter 方法,而 parseObject() 由于多执行了 JSON.toJSON(obj),所以在处理过程中会调用反序列化目标类的所有 setter 和 getter 方法。parseObject() 的源代码如下:

public static JSONObject parseObject(String text) { Object obj = parse(text); if (obj instanceof JSONObject) { return (JSONObject) obj; } return (JSONObject) JSON.toJSON(obj); }

举个简单的例子:

public class FastJsonTest {    public String name; public String age; public FastJsonTest() throws IOException{ } public void setName(String test) { System.out.println("name setter called"); this.name = test; } public String getName() { System.out.println("name getter called"); return this.name; } public String getAge(){ System.out.println("age getter called"); return this.age; } public static void main(String[] args) { Object obj = JSON.parse("{\"@type\":\"fastjsontest.FastJsonTest\",\"name\":\"thisisname\", \"age\":\"thisisage\"}"); System.out.println(obj); Object obj2 = JSON.parseObject("{\"@type\":\"fastjsontest.FastJsonTest\",\"name\":\"thisisname\", \"age\":\"thisisage\"}"); System.out.println(obj2); } }

上述代码运行后可以看到,执行parse() 时,只有 setName() 会被调用。执行parseObject() 时,setName()、getAge()、getName() 均会被调用。

为什么会触发getOutputProperties()

感觉上 parse() 进行反序列化创建Java类应该只会调用 setter 方法进行成员变量赋值才对,会什么会触发TemplatesImpl类中的 getOutputProperties() 方法呢?

另外 _outputProperties 成员变量和 getOutputProperties() 明明差了一个_字符,是怎么被 FastJson 关联上的?

如上一小节所述,parse() 进行反序列化时其实会调用某些特定的 getter 方法进行字段解析,而 TemplatesImpl类中的 getOutputProperties() 方法恰好满足这一条件。

FastJson反序列化到Java类时主要逻辑如下:

  1. 获取并保存目标Java类中的成员变量、setter、getter。
  2. 解析JSON字符串,对字段逐个处理,调用相应的setter、getter进行变量赋值。

我们先看第一步,这里由 JavaBeanInfo.build() 进行处理,FastJson会创建一个filedList数组,用来保存目标Java类的成员变量以及相应的setter或getter方法信息,供后续反序列化字段时调用。

filedList大致结构如下:

[    {        name:"outputProperties",        method:{            clazz:{},            name:"getOutputProperties",            returnType:{},            ...        }    }]

FastJson并不是直接反射获取目标Java类的成员变量的,而是会对setter、getter、成员变量分别进行处理,智能提取出成员变量信息。逻辑如下:

  1. 识别setter方法名,并根据setter方法名提取出成员变量名。如:识别出setAge()方法,FastJson会提取出age变量名并插入filedList数组。
  2. 通过clazz.getFields()获取成员变量。
  3. 识别getter方法名,并根据getter方法名提取出成员变量名。

可以看到在 JavaBeanInfo.build() 中,有一段代码会对getter方法进行判断,在某些特殊条件下,会从getter方法中提取出成员变量名并附加到filedList数组中。而TemplatesImpl类中的 getOutputProperties() 正好满足这个特定条件。getter方法的处理代码为:

JavaBeanInfo.javapublic static JavaBeanInfo build(Class
clazz, Type type, PropertyNamingStrategy propertyNamingStrategy) { ... for (Method method : clazz.getMethods()) { // getter methods String methodName = method.getName(); if (methodName.length() < 4) { continue; } if (Modifier.isStatic(method.getModifiers())) { continue; } if (methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))) { if (method.getParameterTypes().length != 0) { continue; } // 关键条件 if (Collection.class.isAssignableFrom(method.getReturnType()) // || Map.class.isAssignableFrom(method.getReturnType()) // || AtomicBoolean.class == method.getReturnType() // || AtomicInteger.class == method.getReturnType() // || AtomicLong.class == method.getReturnType() // ) { String propertyName; JSONField annotation = method.getAnnotation(JSONField.class); if (annotation != null && annotation.deserialize()) { continue; } if (annotation != null && annotation.name().length() > 0) { propertyName = annotation.name(); } else { propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); } FieldInfo fieldInfo = getField(fieldList, propertyName); if (

转载于:https://www.cnblogs.com/wszme/p/9568460.html

你可能感兴趣的文章
将Oracle的语言从中文修改为英文
查看>>
matlab编译错误代码中英对照
查看>>
Python 元组
查看>>
hbase(ERROR: org.apache.hadoop.hbase.ipc.ServerNotRunningYetException: Server is not running yet)
查看>>
[ZJOI2010]count 数字计数
查看>>
多校4 1001 Olympiad
查看>>
hdu1085 Holding Bin-Laden Captive!
查看>>
hdu4811 Ball
查看>>
Docker实践--搭建Yapi测试平台
查看>>
align-content 与 align-items 区别
查看>>
a链接中,name属性的应用
查看>>
Java精选笔记_多线程(创建、生命周期及状态转换、调度、同步、通信)
查看>>
java Session统计在线用户,并且显示在线用户
查看>>
spring boot集成jpa(mysql)
查看>>
js实现的玫瑰花
查看>>
大话设计模式之责任链模式
查看>>
记录libreoffice实现office转pdf(适用于windows、linux)
查看>>
Python爬虫入门这一篇就够了
查看>>
彻底卸载Cygwin
查看>>
【转】安卓开发一个月之心得(广告平台篇)
查看>>