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响应:
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