Java安全初探-RMI篇

Java RMI初识

Java RMI 定义

Java RMI(Java Remote Method Invocation),即Java远程方法调用。是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。 Java RMI 使用 JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现,使得客户端运行的程序可以调用远程服务器上的对象。是实现RPC的一种方式。

JRMP:Java Remote Message Protocol ,Java 远程消息交换协议。这是运行在Java RMI之下、TCP/IP之上的线路层协议。

注:Java RMI默认使用JRMP协议,而Weblogic RMI使用的是T3协议,此处应进行区分

RMI的交互

此处引用文章JAVA RMI 原理和使用浅析的一张图演示RMI的交互过程

对于RMI流程的解释,网上有很多不错的回答,此处不过多阐述。通俗来讲,便是RMI Registry作为client和server的中间人,假设服务端是商品仓库,客户端是购买者,则RMI Registry就是中介,只负责告诉客户可以售卖的商品相关信息。仓库在中介处登记可售商品,客户从中介处查看可购买的商品。客户从中介处获得商品的相关信息,然后交给跑腿(存根stub)去跟仓库人员(骨架skeleton)取货,双方商品信息确认一致,进行交易,客户获得商品。(可能比喻有点不恰当,别揍我qwq...

RMI 尝试

此处为了更能体会rmi原理,不把server和client放在同一个机器,而是将服务器放在虚拟机中,测试环境均为1.8u211

  1. 编写远程服务接口,该接口必须继承 java.rmi.Remote 接口,方法必须抛出java.rmi.RemoteException 异常;

  2. 编写远程接口实现类,该实现类必须继承 java.rmi.server.UnicastRemoteObject 类;

  3. 运行 RMI 编译器(rmic),创建客户端 stub 类和服务端 skeleton 类;

  4. 启动一个 RMI 注册表,以便驻留这些服务;

  5. 在 RMI 注册表中注册服务;

  6. 客户端查找远程对象,并调用远程方法;

注意:这里踩了个小坑,RMI 抛出异常 no security manager: RMI class loader disabled,新手容易遇到这个问题。这是因为在编译class文件的时候,这个class文件内部已经包含了package test.org;这样的内容,如果在部署的时候,不严格按照这个目录部署的话,服务器就会找不到。所以服务器和客户端在路径上要保持一致。

Server测试例

org
    └─test
    	├─RMI
    	│      	RMIServer.java
    	│
    	└─Server
            	Hello.java
//RMIServer.java
package org.test.RMI;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

import org.test.Server.Hello;

public class RMIServer {
    public class RemoteHelloWorld extends UnicastRemoteObject implements Hello {
        protected RemoteHelloWorld() throws RemoteException {
            super();
        }
        public String hello() throws RemoteException {
            System.out.println("call from");
            return "Hello DEADF1SH_CAT~";
        }
    }

    private void start() throws Exception {
        RemoteHelloWorld h = new RemoteHelloWorld();
        LocateRegistry.createRegistry(1099);
        Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
    }
    
    public static void main(String[] args) throws Exception {
        new RMIServer().start();
    }
}
//Hello.java
package org.test.Server;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    public String hello() throws RemoteException;
}

Client测试例

org
    └─test
        ├─client
        │      TrainMain.java
        │
        └─Server
                Hello.java
//TrainMain.java
package org.test.client;

import java.rmi.Naming;

import org.test.Server.Hello;

public class TrainMain {
    public static void main(String[] args) throws Exception {
        Hello hello = (Hello) Naming.lookup("rmi://192.168.247.128:1099/Hello");
        String ret = hello.hello();
        System.out.println(ret);
    }
}
//Hello.java
package org.test.Server;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    public String hello() throws RemoteException;
}

服务器输出

客户端输出

可以看出客户端成功调用了服务器的RemoteHelloWorld对象的hello方法

RMI数据包分析

对上述调用过程进行抓包分析

  • 1-5为tcp三次握手和网关转发报文
  • 6-12为RMI通信数据(其中TCP报文为确认报文)

来看看9号RMI Call报文(远程对象请求)

SerializationDumper这个工具对Java序列化数据进行分析

F:\Java>java -jar SerializationDumper.jar aced00057722000000000000000000000000000000000000000000000000000244154dc9d4e63bdf74000548656c6c6f

STREAM_MAGIC - 0xac ed  #声明使用了序列化协议
STREAM_VERSION - 0x00 05 #序列化协议版本
Contents
  TC_BLOCKDATA - 0x77 #块数据
    Length - 34 - 0x22
    Contents - 0x000000000000000000000000000000000000000000000000000244154dc9d4e63bdf
  TC_STRING - 0x74 #字符串
    newHandle 0x00 7e 00 00
    Length - 5 - 0x00 05
    Value - Hello - 0x48656c6c6f

Object Serialization Stream Protocol文档中,可以发现TC_BLOCKDATA 这部分对应的是 contents -> content -> blockdata -> blockdatashort , TC_STRING 这部分对应的是 contents -> content -> object-> newString。整个序列化数据含义并不难猜,其实就是告诉我们获取远程的Hello对象。

接下来看看11号RMI ReturnData报文(返回远程对象)

F:\Java> java -jar .\SerializationDumper.jar aced0005770f0175f02f4b00000170fd2fe646800e737d00000002000f6a6176612e726d692e52656d6f746500156f72672e746573742e5365727665722e48656c6c6f70787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b7078707372002d6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c65720000000000000002020000707872001c6a6176612e726d692e7365727665722e52656d6f74654f626a656374d361b4910c61331e0300007078707738000a556e6963617374526566000f3139322e3136382e3234372e3132380000c3ec8f6141e4b20d3e0e75f02f4b00000170fd2fe64680010178   

STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
  TC_BLOCKDATA - 0x77
    Length - 15 - 0x0f
    Contents - 0x0175f02f4b00000170fd2fe646800e
  TC_OBJECT - 0x73
    TC_PROXYCLASSDESC - 0x7d
      newHandle 0x00 7e 00 00
      Interface count - 2 - 0x00 00 00 02
      proxyInterfaceNames
        0:
          Length - 15 - 0x00 0f
          Value - java.rmi.Remote - 0x6a6176612e726d692e52656d6f7465
        1:
          Length - 21 - 0x00 15
          Value - org.test.Server.Hello - 0x6f72672e746573742e5365727665722e48656c6c6f
      classAnnotations
        TC_NULL - 0x70
        TC_ENDBLOCKDATA - 0x78
      superClassDesc
        TC_CLASSDESC - 0x72
          className
            Length - 23 - 0x00 17
            Value - java.lang.reflect.Proxy - 0x6a6176612e6c616e672e7265666c6563742e50726f7879
          serialVersionUID - 0xe1 27 da 20 cc 10 43 cb
          newHandle 0x00 7e 00 01
          classDescFlags - 0x02 - SC_SERIALIZABLE
          fieldCount - 1 - 0x00 01
          Fields
            0:
              Object - L - 0x4c
              fieldName
                Length - 1 - 0x00 01
                Value - h - 0x68
              className1
                TC_STRING - 0x74
                  newHandle 0x00 7e 00 02
                  Length - 37 - 0x00 25
                  Value - Ljava/lang/reflect/InvocationHandler; - 0x4c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b
          classAnnotations
            TC_NULL - 0x70
            TC_ENDBLOCKDATA - 0x78
          superClassDesc
            TC_NULL - 0x70
    newHandle 0x00 7e 00 03
    classdata
      java.lang.reflect.Proxy
        values
          h
            (object)
              TC_OBJECT - 0x73
                TC_CLASSDESC - 0x72
                  className
                    Length - 45 - 0x00 2d
                    Value - java.rmi.server.RemoteObjectInvocationHandler - 0x6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c6572
                  serialVersionUID - 0x00 00 00 00 00 00 00 02
                  newHandle 0x00 7e 00 04
                  classDescFlags - 0x02 - SC_SERIALIZABLE
                  fieldCount - 0 - 0x00 00
                  classAnnotations
                    TC_NULL - 0x70
                    TC_ENDBLOCKDATA - 0x78
                  superClassDesc
                    TC_CLASSDESC - 0x72
                      className
                        Length - 28 - 0x00 1c
                        Value - java.rmi.server.RemoteObject - 0x6a6176612e726d692e7365727665722e52656d6f74654f626a656374
                      serialVersionUID - 0xd3 61 b4 91 0c 61 33 1e
                      newHandle 0x00 7e 00 05
                      classDescFlags - 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLE
                      fieldCount - 0 - 0x00 00
                      classAnnotations
                        TC_NULL - 0x70
                        TC_ENDBLOCKDATA - 0x78
                      superClassDesc
                        TC_NULL - 0x70
                newHandle 0x00 7e 00 06
                classdata
                  java.rmi.server.RemoteObject
                    values
                    objectAnnotation
                      TC_BLOCKDATA - 0x77
                        Length - 56 - 0x38
                        Contents - 0x000a556e6963617374526566000f3139322e3136382e3234372e3132380000c3ec8f6141e4b20d3e0e75f02f4b00000170fd2fe646800101 #里面包含RMI Server和端口
                      TC_ENDBLOCKDATA - 0x78
                  java.rmi.server.RemoteObjectInvocationHandler
                    values
      <Dynamic Proxy Class>

内容突然多了起来,不过看到一些跟java.lang.reflect.Proxy对象有关的东西,其实就是返回了调用远程方法的服务器地址和端口。怎么确定呢,观察后续tcp交互的报文即可知道。

再看19号数据包,也是一串aced开头的反序列数据

丢进去工具分析一下序列化数据

F:\Java> java -jar .\SerializationDumper.jar 50aced000577220000000000000002000000000000000000000000000000000001f6b6898d8bf28643757200185b4c6a6176612e726d692e7365727665722e4f626a49443b871300b8d02c647e02000070787000000001737200156a6176612e726d692e7365727665722e4f626a4944a75efa128ddce55c0200024a00066f626a4e756d4c000573706163657400154c6a6176612f726d692f7365727665722f5549443b7078708f6141e4b20d3e0e737200136a6176612e726d692e7365727665722e5549440f12700dbf364f12020003530005636f756e744a000474696d65490006756e69717565707870800100000170fd2fe64675f02f4b77088000000000000000737200126a6176612e726d692e6467632e4c65617365b0b5e2660c4adc340200024a000576616c75654c0004766d69647400134c6a6176612f726d692f6467632f564d49443b70787000000000000927c0737200116a6176612e726d692e6467632e564d4944f8865bafa4a56db60200025b0004616464727400025b424c000375696471007e0003707870757200025b42acf317f8060854e002000070787000000008ed0c29a151acf1bb7371007e0005800100000170fd4ea68fcc0083e6          
RMI Call - 0x50
STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
  TC_BLOCKDATA - 0x77
    Length - 34 - 0x22
    Contents - 0x0000000000000002000000000000000000000000000000000001f6b6898d8bf28643
  TC_ARRAY - 0x75
    TC_CLASSDESC - 0x72
      className
        Length - 24 - 0x00 18
        Value - [Ljava.rmi.server.ObjID; - 0x5b4c6a6176612e726d692e7365727665722e4f626a49443b
      serialVersionUID - 0x87 13 00 b8 d0 2c 64 7e
      newHandle 0x00 7e 00 00
      classDescFlags - 0x02 - SC_SERIALIZABLE
      fieldCount - 0 - 0x00 00
      classAnnotations
        TC_NULL - 0x70
        TC_ENDBLOCKDATA - 0x78
      superClassDesc
        TC_NULL - 0x70
    newHandle 0x00 7e 00 01
    Array size - 1 - 0x00 00 00 01
    Values
      Index 0:
        (object)
          TC_OBJECT - 0x73
            TC_CLASSDESC - 0x72
              className
                Length - 21 - 0x00 15
                Value - java.rmi.server.ObjID - 0x6a6176612e726d692e7365727665722e4f626a4944
              serialVersionUID - 0xa7 5e fa 12 8d dc e5 5c
              newHandle 0x00 7e 00 02
              classDescFlags - 0x02 - SC_SERIALIZABLE
              fieldCount - 2 - 0x00 02
              Fields
                0:
                  Long - L - 0x4a
                  fieldName
                    Length - 6 - 0x00 06
                    Value - objNum - 0x6f626a4e756d
                1:
                  Object - L - 0x4c
                  fieldName
                    Length - 5 - 0x00 05
                    Value - space - 0x7370616365
                  className1
                    TC_STRING - 0x74
                      newHandle 0x00 7e 00 03
                      Length - 21 - 0x00 15
                      Value - Ljava/rmi/server/UID; - 0x4c6a6176612f726d692f7365727665722f5549443b
              classAnnotations
                TC_NULL - 0x70
                TC_ENDBLOCKDATA - 0x78
              superClassDesc
                TC_NULL - 0x70
            newHandle 0x00 7e 00 04
            classdata
              java.rmi.server.ObjID
                values
                  objNum
                    (long)-72056500129022450 - 0x8f 61 41 e4 b2 0d 3e 0e
                  space
                    (object)
                      TC_OBJECT - 0x73
                        TC_CLASSDESC - 0x72
                          className
                            Length - 19 - 0x00 13
                            Value - java.rmi.server.UID - 0x6a6176612e726d692e7365727665722e554944
                          serialVersionUID - 0x0f 12 70 0d bf 36 4f 12
                          newHandle 0x00 7e 00 05
                          classDescFlags - 0x02 - SC_SERIALIZABLE
                          fieldCount - 3 - 0x00 03
                          Fields
                            0:
                              Short - S - 0x53
                              fieldName
                                Length - 5 - 0x00 05
                                Value - count - 0x636f756e74
                            1:
                              Long - L - 0x4a
                              fieldName
                                Length - 4 - 0x00 04
                                Value - time - 0x74696d65
                            2:
                              Int - I - 0x49
                              fieldName
                                Length - 6 - 0x00 06
                                Value - unique - 0x756e69717565
                          classAnnotations
                            TC_NULL - 0x70
                            TC_ENDBLOCKDATA - 0x78
                          superClassDesc
                            TC_NULL - 0x70
                        newHandle 0x00 7e 00 06
                        classdata
                          java.rmi.server.UID
                            values
                              count
                                (short)-32767 - 0x80 01
                              time
                                (long)-47192506 - 0x00 00 01 70 fd 2f e6 46
                              unique
                                (int)1978675019 - 0x75 f0 2f 4b
  TC_BLOCKDATA - 0x77
    Length - 8 - 0x08
    Contents - 0x8000000000000000
  TC_OBJECT - 0x73
    TC_CLASSDESC - 0x72
      className
        Length - 18 - 0x00 12
        Value - java.rmi.dgc.Lease - 0x6a6176612e726d692e6467632e4c65617365
      serialVersionUID - 0xb0 b5 e2 66 0c 4a dc 34
      newHandle 0x00 7e 00 07
      classDescFlags - 0x02 - SC_SERIALIZABLE
      fieldCount - 2 - 0x00 02
      Fields
        0:
          Long - L - 0x4a
          fieldName
            Length - 5 - 0x00 05
            Value - value - 0x76616c7565
        1:
          Object - L - 0x4c
          fieldName
            Length - 4 - 0x00 04
            Value - vmid - 0x766d6964
          className1
            TC_STRING - 0x74
              newHandle 0x00 7e 00 08
              Length - 19 - 0x00 13
              Value - Ljava/rmi/dgc/VMID; - 0x4c6a6176612f726d692f6467632f564d49443b
      classAnnotations
        TC_NULL - 0x70
        TC_ENDBLOCKDATA - 0x78
      superClassDesc
        TC_NULL - 0x70
    newHandle 0x00 7e 00 09
    classdata
      java.rmi.dgc.Lease
        values
          value
            (long)600000 - 0x00 00 00 00 00 09 27 c0
          vmid
            (object)
              TC_OBJECT - 0x73
                TC_CLASSDESC - 0x72
                  className
                    Length - 17 - 0x00 11
                    Value - java.rmi.dgc.VMID - 0x6a6176612e726d692e6467632e564d4944
                  serialVersionUID - 0xf8 86 5b af a4 a5 6d b6
                  newHandle 0x00 7e 00 0a
                  classDescFlags - 0x02 - SC_SERIALIZABLE
                  fieldCount - 2 - 0x00 02
                  Fields
                    0:
                      Array - [ - 0x5b
                      fieldName
                        Length - 4 - 0x00 04
                        Value - addr - 0x61646472
                      className1
                        TC_STRING - 0x74
                          newHandle 0x00 7e 00 0b
                          Length - 2 - 0x00 02
                          Value - [B - 0x5b42
                    1:
                      Object - L - 0x4c
                      fieldName
                        Length - 3 - 0x00 03
                        Value - uid - 0x756964
                      className1
                        TC_REFERENCE - 0x71
                          Handle - 8257539 - 0x00 7e 00 03
                  classAnnotations
                    TC_NULL - 0x70
                    TC_ENDBLOCKDATA - 0x78
                  superClassDesc
                    TC_NULL - 0x70
                newHandle 0x00 7e 00 0c
                classdata
                  java.rmi.dgc.VMID
                    values
                      addr
                        (array)
                          TC_ARRAY - 0x75
                            TC_CLASSDESC - 0x72
                              className
                                Length - 2 - 0x00 02
                                Value - [B - 0x5b42
                              serialVersionUID - 0xac f3 17 f8 06 08 54 e0
                              newHandle 0x00 7e 00 0d
                              classDescFlags - 0x02 - SC_SERIALIZABLE
                              fieldCount - 0 - 0x00 00
                              classAnnotations
                                TC_NULL - 0x70
                                TC_ENDBLOCKDATA - 0x78
                              superClassDesc
                                TC_NULL - 0x70
                            newHandle 0x00 7e 00 0e
                            Array size - 8 - 0x00 00 00 08
                            Values
                              Index 0:
                                (byte)-19 - 0xed
                              Index 1:
                                (byte)12 - 0x0c
                              Index 2:
                                (byte)41 (ASCII: )) - 0x29
                              Index 3:
                                (byte)-95 - 0xa1
                              Index 4:
                                (byte)81 (ASCII: Q) - 0x51
                              Index 5:
                                (byte)-84 - 0xac
                              Index 6:
                                (byte)-15 - 0xf1
                              Index 7:
                                (byte)-69 - 0xbb
                      uid
                        (object)
                          TC_OBJECT - 0x73
                            TC_REFERENCE - 0x71
                              Handle - 8257541 - 0x00 7e 00 05
                            newHandle 0x00 7e 00 0f
                            classdata
                              java.rmi.server.UID
                                values
                                  count
                                    (short)-32767 - 0x80 01
                                  time
                                    (long)-45177201 - 0x00 00 01 70 fd 4e a6 8f
                                  unique
                                    (int)-872381466 - 0xcc 00 83 e6

数据太多,基于自身知识有限,先留个坑(别打我,真不会哇,后面专门开一篇文章分析本篇文章的几份序列化数据,不过通过这波抓包分析流程,结合上面的流程图,相信大家对RMI调用流程也有一定的理解了。

相关链接

posted @ 2020-03-22 00:20  DEADF1SH_CAT  阅读(823)  评论(0编辑  收藏  举报