Fastjson68版本绕过autotype原理及利用场景分析

林哲

发表文章数:1017

专业SEO优化

  • 正规SEO优化手法
  • 承诺流量+权重提升
  • 强大的团队解决问题
  • 全心全意的服务
  • 立即咨询

    热门标签

    ,
    首页 » WEB安全 » Fastjson68版本绕过autotype原理及利用场景分析

    文章目录

    • 引言
    • 原理
    • 利用场景分析

    引言

    fastjson 68版本前一阵子有些闹得沸沸扬扬的,我这边也一直忙着写字节码扫描器没太用心关注,今天看到fastjson代码已经跟进到71版本了,所以对68和69版本的代码做了一下比对,看了一下修复代码,这里对68版本fastjson的RCE漏洞做一下原理以及利用场景的分析。

    注:其实最初在5月10号的时候我这边就已经看到了68版本的一种利用方式,基于Throwable子类的利用方式,不过这种方式只是68版本利用方式中的一种。

    原理

    fastjson的漏洞跟进的比较多的情况下,可以明白一个基本的套路就是,不管绕过怎么样的风骚,修复代码大部分都在ParserConfig类的checkAutoType里面,所以就话不多说,把68版本和69版本的ParserConfig类做个比较,看到改动还是很少的。

    Fastjson68版本绕过autotype原理及利用场景分析
     

    基本上一看可以看出是和expectClass有关,所以在函数的上上下下看了一下这个变量,可以归并一下发现的信息:

    1、expectClass不为代码中的那些类的时候可以将expectClassFlag设置为true

    Fastjson68版本绕过autotype原理及利用场景分析
     

    2、当expectClassFlag为true的时候,即使fastjson的autoype为false我们也能生成期望类的实例。

    Fastjson68版本绕过autotype原理及利用场景分析
     

    OK但从上诉两点,我们就可以看到借由expectClass我们是可以绕过fastjson的autotype安全限制的,这个安全通告相符合,代表我们走在正确的方向上。

    但是在阅读checkAutoType函数中expectClass的代码的时候,也发现了其中一些会限制Gadget的点,

    1、黑名单检测逻辑是放在loadClass之前的,也就是说我们的Gadget将依旧受到黑名单的限制。(代码太长,我就不贴了)

    2、Gadget必须实现了expectClass接口(或是expectClass的子类),才能成功生成Gadget的实例。

    Fastjson68版本绕过autotype原理及利用场景分析
     

    上面便是阅读代码得到的关键性信息了,接下来就要思考一下expectClass的问题了,第一个问题,expectClass是从哪里来的,看一下checkAutoType函数,

    public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features)

    很清晰,expectClass就是直接传给checkAutoType函数的,那么接下来我们需要去寻找,究竟哪些地方会给checkAutoType函数传expectClass,全局搜索一下,可以看到场景非常少,

    1、JavaBeanDeserializer类的deserialze函数

    2、ThrowableDeserializer类的deserialze函数

    关于第二种场景,我这边5月10号就到了别的大佬的分析,有兴趣大家可以去看一下,我就不再赘述,这里着重讲第一种。(当然其实就原理而言完全是一回事。)

    DefaultJSONParser调用parseObject,用@type生成的clazz实例会紧接着传入JavaBeanDeserializer类的deserialze方法的type参数中,并继续解析json数据,如果json数据中还有@type,则把@type的值作为typeName,type参数作为expectClass传入checkAutoType函数中,

    Fastjson68版本绕过autotype原理及利用场景分析
     

    Fastjson68版本绕过autotype原理及利用场景分析
     

    那根据我们刚刚分析代码得出的结论,如果typeName刚好为expectClass的子类,那么接下来就能生成typename的对象,从而达成绕过autotype的目的。

    但是,这里一定要注意一个特别重要的问题,由于默认autotype是关着的,那么我们又怎么样去用@type来生成传给deserialze的clazz呢,下面我就先给出目前fastjson在autotype关闭的情况下能生成的clazz的范围:

    1、cache mapping:48版本以前fastjson允许用户通过{“@type”:”java.lang.Class”,”val”:”com.evilClass”}的形式向mapping里面添加恶意类,这样不需要依赖autotype可以直接从cahce的mapping里获取clazz,但是48版本已经修复该问题。当然cache mapping在刚fastjson启动的时候就已经放了不少clazz,加载的时候不受autotype限制。

    Fastjson68版本绕过autotype原理及利用场景分析
     

    2、白名单:不赘述,白名单的目的就是不受autotype的限制嘛。不过新版本白名单已经被加密,需要爆破一下。

    3、默认deserializers的buckets(在PaserConfig类的initDeserializers函数中初始化):可以把fastjson理解为一个编译器,它在进行初始化的时候也需要加载一些基础类型的对象,这些对象为了组件的正常工作是必须的。

    Fastjson68版本绕过autotype原理及利用场景分析
     

    所以我们需要的clazz就是要从上诉列举的三种情况里面寻找到,与此同时保证它不在黑名单里面。

    OK,全部的分析已经到位,我们来汇总一下,看看poc究竟要怎么写:

    1、首先要用@type来生成一个clazz(不受autotype影响的)。从而把这个clazz传入deserialze函数的exceptClass中,要保证clazz不能为以下类。(这个是68版本的,69版本又添加了三个。)

    Fastjson68版本绕过autotype原理及利用场景分析
     

    2、紧跟在生成在第一个@type后面,再跟一个@type,它的value不能是黑名单里面的类,而且必须是第一个clazz的子类。

    之后便能生成一个不受autotype影响的clazz,以达到利用效果。

    关于漏洞的复现,为了方便起见,我就直接去拿了69版本被拉黑而68版本没被拉黑的AutoCloseable接口来构造poc了。

    因为想要利用成功必须保证第二个clazz实现AutoCloseable的接口,恶意类难找,我们只聊原理,我就随便写了一个利用类。

    package defaultpack;
    import com.alibaba.fastjson.JSON;
    import com.sun.rowset.JdbcRowSetImpl;
    import org.h2.tools.SimpleResultSet;
    import java.lang.reflect.Field;
    public class Person implements AutoCloseable{
        private String name;
        private int age;
        private String gender;
        public Person() {
            System.out.println("no-arg construct invoked!!!");
        }
        public Person(String name, int age, String gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            System.out.println("getAge invoked!!!");
            return age;
        }
        public void setAge(int age) {
            this.age = age;
            System.out.println("setAge invoked!!!");
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        @Override
        public void close() throws Exception {
        }
    }

    利用的poc如下,

    String payload = "{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"defaultpack.Person\",\"age\":\"13\"}";
    JSON.parseObject(payload);

    成功利用的截图如下,可以看到在68版本autype默认为关的情况下,依旧成功调用了Person类的setAGe方法。:

    Fastjson68版本绕过autotype原理及利用场景分析
     

    利用场景分析

    可以从上面的分析看出,虽然在原理层面上,的确存在着代码执行的风险,且绕过了autotype机制,但是这个利用受到了多方面限制:

    1、黑名单限制

    2、漏洞利用类必须拥有一个在autotype关着的情况下可以生成实例的父类(目前在68版本我已知的是Throwable和AutoCloseable)。

    所以因为以上两点的限制,就可以发现利用是非常局限的,当然也不排除黑客大佬们思路广阔而笔者才疏学浅的可能性,因此我也仅在这里给出自己的看法。

    *本文作者:平安银行应用安全团队@Glassy,转载请注明来自ALA林哲

    分享到:
    赞(0)

    评论 抢沙发

    7 + 1 =


    Vieu4.5主题
    专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
    切换注册

    登录

    忘记密码 ?

    切换登录

    注册