Allbet

usdt充值接口(caibao.it):深入学习rmi事情原理

Allbet登录网址 2020年12月22日 科技 30 0

1. 前言

随着对rmi反序列化的深入学习,发现它的攻击面并没有一最先明白的浅易。主要照样在看这篇针对RMI服务的九重攻击时,发现攻击中涉及的类和通讯协议足以让我单独花时间研究一阵子了。因此这篇算是我单独研究rmi挪用流程和源码的总结

2. 回首

先回首一下rmi事情的流程:

  1. 注册端开启注册服务
  2. 服务端在注册端通过String - Object的映射关系绑定工具
  3. 客户端通过一个字符串向注册端查询获取到操作远程工具的stub(?)
  4. 客户端通过stub来执行远程方式

在整个流程中,涉及了两组关系:

  • 客户端——注册端
  • 客户端——服务端

这里的两个客户端都是相对而言的,并不是指代同一个工具。好比,注册端开放在192.168.242.1:1099端口,下述代码的行为就是我说的第一个客户端:

Registry registry = LocateRegistry.getRegistry("192.168.242.1", 1099);
String[] lists = registry.list();
registry.lookup("Hello");
registry.bind("las", new myRemoteObj());  // only work for localhost

再好比,当通过lookup方式获取到一个工具后,对该工具的操作就是指代第二种实体关系:

...
myInterfACE obj = registry.lookup("Hello");
obj.myMethod("param");

上面两种实体之间的通讯细节和协议,就是我接下来要实验注释的器械。

由于剖析rmi源码也是为了能够更深入的学习rmi平安问题,以是我列出了剖析中的一些关注点以助于明白:

  • 当服务端要抛出一个错误时,它的挪用栈是怎样的。这个错误是怎样被发送给客户端的。
  • 客户端的DGCClient工具提议dirty call的流程。这里现实上就是ysoserial中JRMPClient载荷行使的地方。
  • UnicastServerRef,dispatch方式的两个支。

3. 客户端—注册端

注册端

简朴来说,注册端监听在1099端口,剖析客户端提议的所有毗邻,判断它们是listbindrebindlookupuNBind这五种行为的哪一种,并挪用响应的方式来处置。不外在此之前,它们还会通报一些数据包用于认证和信息交流。好比,下面是客户端在执行lookup方式时所发生的流量:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第1张

不外注册端不只会处置这些api挪用,后面会看到,注册端还会处置dgc和一些心跳包的发送。

剖析清晰了注册端的行为,就能搞清晰客户端所做的事情,两者是相对的。

我们首先剖析注册端。

一样平常来说,注册端的要害代码如下:

IRemoteHelloWorld remoteHelloWorld = new RemoteHelloWorldImpl();
Registry registry = LocateRegistry.createRegistry(1099);
registry.bind("Hello", remoteHelloWorld);

处置网络数据前的挪用链

进入createRegistry方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第2张

这里获取到的是一个RegistryImpl工具。需要说明的是,客户端一样平常挪用的是LocateRegistry.getRegsitry(ip,port),它获取到的是一个RegistryImpl_Stub工具。故可知,stub和skel的观点是相对而言的,并不只存在于服务端和客户端之间。

进入RegistryImpl的组织方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第3张

可以看到,无论是if照样else语句块中,焦点代码都是:

LiveRef var2 = new LiveRef(id, var1);
this.setup(new UnicastServerRef(var2));

这里之以是有个if,是为了保证当程序设置了SecurityManager后,只有当rmi注册服务开放在1099端口时才气执行焦点代码。在设置SecurityManager计谋后,程序自己可能会没有特权去执行焦点代码,因此需要通过AccessController.doPrivileged的形式去赋予特权。关于AccessController可参见毗邻。

总的来说,这里的if相当于提供了一个平安计谋:程序员可以通过设置securityManager来保证rmi服务只能开放在1099端口。

接下来进入this.setup()方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第4张

这里执行了UnicastServerRef上的exportObject方式,这也是第一次看到exportObject方式泛起。执行了它之后,客户端就可以挪用注册端上的api了,就好像注册端(object)被露出(export)在了1099端口一样。

在openjdk代码的注释中注释的则更detAIl:

/**
     * Export this object, create the skeleton and stubs for this
     * dispatcher.  Create a stub based on the type of the impl,
     * initialize it with the appropriate remote reference. Create the
     * target defined by the impl, dispatcher (this) and stub.
     * Export that target via the Ref.
     */

说明在这个方式里,会建立注册端响应的stub工具和skeleton工具。

继续跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第5张

这里先跟进Util.createProxy()方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第6张

发现最后执行了createStub方式,这个方式通过反射实例化了sun.rmi.registryImpl_Stub工具并将其作为返回值。

这里就知道了,var5就是一个registryImpl_Stub工具。

同时这里也挪用了this.setSkeleton来设置一个registryImpl_Skel

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第7张

接下来回到刚刚的exportObject方式中,发现它建立了一个Target工具var6,然后挪用了this.ref.exportObject(var6),这里的ref,就是我们前面建立UnicastServerRef时传入的liveRef工具:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第8张

于是跟进liveRef,exportObject()方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第9张

跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第10张

继续跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第11张

这里的this.listen()方式是重点,执行它之后注册端就最先监听1099端口了。于是我们跟进看它的内部逻辑:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第12张

这里会进入到第一个if代码块内。

可以看到这里又泛起了AccessController.doPrivileged()方式。由于它最终会挪用到TCPTraNSport.AcceptLoop,run方式,我们直接在这个方式下断点并跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第13张

跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第14张

下面的代码都是catch块就不贴出来了。

这里的this.serverSocket就是在TCPTransport,listen方式中建立的,它监听的端口就是我们最最先传入的port。

接下来进入try中的代码块,它实在又建立了新线程。跟进ConnectionHandler,run方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第15张

再跟进this.run0()方式。

处置网络数据

需要说明的是,从这个方式最先,就能看到注册端最先读取并剖析客户端通报的TCP数据,凭据字段的类型来执行响应的bindlist等操作,并将效果返回。

由于该方式比较长,以是我逐段举行剖析。

前面的一些代码主要是设置TCP的一些参数,不管,看下面的部门:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第16张

这里是第一次从输入流读取数据,接下来会凭据var6的值判断进入哪个if块:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第17张

这里的1347375956转为十六进制再转为字符串就是:POST。说明这里的逻辑是判断它是否为http流量,一样平常不会进入这个分支。

我们进入第二个if。1246907721转为十六进制实在是0x4a524d49,这实在就是rmi协议的魔术头,同时第二个short字段示意版本:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第18张

在这个if分支里又读取了一个字节存到var15,然后进入switch。这里一样平常来说读取到的是0x4b,即75:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第19张

进入case后,由于已经剖析完了第一个接受包,注册端最先组织第一个回复包:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第20张

直到var10.flush();,注册端缓冲区的数据被发送出去。

接下来的代码:

String var16 = var5.readUTF();
int var17 = var5.readInt();

用于剖析客户端发送的第二个数据包,不外这个数据包似乎没起到什么作用。第二个数据包内容如下:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第21张

接下来进入TCPTransport.this.handleMessages(var14, true)。注重第二个参数为true,它让接下来的代码中的while语句不停循环。见红框圈处:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第22张

这里int var5 = var4.read()实在已经最先剖析客户端发送的第三个数据包了(说明注册端并没有回复第二个数据包,从流量图也能看出),第三个数据包的内容将在之后贴出。初看这个var5是int好像是读取4个字节,然则跟进var4.read()能看到实在照样读取的一个字节:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第23张

var5的内容实在是示意该数据包是哪种类型。一样平常来说有下面三种:

  • 80,即0x50,示意执行营业方式。这里是挪用注册端的某个方式(如listbind),后面会看到,客户端在执行远程方式时,服务端也会从这里进去。

    例如下述数据包:

    usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第24张

  • 82,即0x52,心跳包(也许),这里可以看到注册端回复了一个字节0x53。例如下面两个数据包:

    usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第25张

  • 84,即0x54DgcAck,如下:

    usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第26张

这里继续跟进80,也就是挪用注册端api方式的case。进入StreamRemoteCall,serviceCall

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第27张

我们首先贴出第三个数据包的内容:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第28张

需要注重的是,我们上面已经读取了一个字节了,接下来的aced之后的内容,按理来说都是序列化的内容了。

然则注重这里的var39 = ObjID.read(var1.getInputStream());,它是从什么地方读取的内容呢?

实在内容是在序列化数据的BlockData块。

读取了ObjID后,又开启了新线程。进入var6.dispatch(),也就是UnicastServerRef,dispatch

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第29张

这里实在是进入this.oldDispatch。继续跟进:

后面在剖析客户端—服务端时可知,若是不进入这个if语句,之后所作的事情实在就是服务端处置客户端挪用远程工具方式的部门。这里留个印象就好。

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第30张

这里的this.skel就是在之前挪用UnicastServerRef,exportObject方式时设置的registryImpl_Skel。跟进registryImpl_Skel,dispatch

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第31张

终于到这里了!这里就是注册端最后挪用各个api(listbind等)的地方。

看一眼客栈:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第32张

不外到这里,我们只跟进了LocateRegistry.createRegistry的内容。注册端的代码另有一条:

registry.bind("Hello", remoteHelloWorld);

万幸是registryImpl,bind的逻辑很简朴:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第33张

这里只是String——obj的映射关系放到了registryImplbindings中。

后续可以看到,客户端执行lookup方式时,注册端就会从registryImplbindings中查询工具:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第34张

注册端剖析完毕。接下来剖析客户端。

图示

注册端挪用LocateRegistry,createRegistry的流程比较复杂,以是截了下图便于更直观的看到挪用关系。

每一个线程单独为一张图。

主线程:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第35张

线程一:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第36张

线程二:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第37张

线程三,从这里最先处置网络数据:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第38张

线程四,又回到了UnicastServerRef方式,最终挪用了RegistryImpl_Skel,dispatch

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第39张

客户端

客户端代码如下:

Registry registry = LocateRegistry.getRegistry("192.168.242.1", 1099);
 registry.lookup("Hello");

开启注册端后最先debug。

首先跟进LocateRegistry,getRegistry方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第40张

继续跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第41张

最后同样挪用Util,createProxy建立了一个registryImpl_Stub工具(这个方式在注册端的UnicastServerRef,exportObject中曾被挪用)。传入的UnicastRef中包罗了ObjIDhostport等信息,用于毗邻注册端:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第42张

到这里可知,客户端挪用LocateRegistry,getRegistry方式获取到的工具是RegistryImpl_Stub

接下来跟进客户端的第二行代码,即RegistryImpl_Stub,lookup

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第43张

super.ref.newCall( this, operations, 2, ...);处会提议前期的握手包(不是tcp的),

然后在super.ref.invoke(var2);处发送lookup的数据。

在接下来的var23=(Remote)var6.readObject()获取到服务端发送的署理工具。

这里的super.ref就是一个unicastRef工具。

super.ref.newCall()

这里先跟进super.ref.newCall

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第44张

再跟进this.ref.getChannel().newConnection(),AKATCPChannel,newConnection

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第45张

跟进this.createConnection(),这部门代码有些长,分两部门列出:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第46张

这里的var3.writeByte(75)就是去组织了客户端发送的第一个握手包,在注册端的剖析中我们知道它实在示意StreamProtocol

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第18张

至于if块中的var3.writeByte(76),应该是在socket不是Reusable时,接纳将握手包和现实数据合在一起的方式(可以看到它没有var3.flush())。

接着var3.writeByte(75)看它之后的代码:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第48张

这里是在读取注册端回复的第一个数据包。长这样,发现它把我们的host和port又发给了我们:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第49张

var3.writeUTF最先,客户端发送第二个数据包:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第50张

到这里为止,客户端发送了两次数据包,处置了注册端的第一个回复。

回到super.ref.newCall

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第44张

,

allbet手机版下载ALLbet6.com

欢迎进入Allbet手机版下载(Allbet Game):www.aLLbetgame.us,欧博官网欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务

,

接下来进入var7 = new StreamRemoteCall(var6, this.ref.getObjID(), var3, var4);

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第52张

这里实在是在组织现实的lookup包了。然则还没有写入工具,只是将一些信息写到了BlockData中。

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第53张

到这里为止,super.ref.newCall()的功效本剖析完毕。该回到RegistryImpl_Stub,lookup剖析下个方式super.ref.invoke。在此之前,需要看到,在lookup中,它先挪用了var3.writeObject(var1)将查询的字符串写入了缓冲区:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第43张

super.ref.invoke()

跟进UnicastRef,invoke

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第55张

跟进StreamRemoteCall,executeCall()

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第56张

首先在this.releaseOutputStream()中将适才的写的数据(主要是lookup的字符串)发送了出去:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第57张

到这里,客户端发送了第三个数据包。

客户端发送这个数据包之后,是期望获得注册端的回复的,由于我们希望通过lookup获取到一个工具,然后基于这个工具来操作远程工具。

我们看一下回复数据包长啥样:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第58张

不太清晰,用SerializationDumper.jar打开看下:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第59张

可以看到,返回的工具是一个继续了java.rmi.Remoteorg.las.remote.IRemoteHelloWorld(自定义)接口的署理工具(TC_PROXYCLASSDESC),同时也需要注重,在TC_BLOCKDATA中也有器械。后面读的一些内容就是从这里拿的。

接着releaseOutputStream的代码就最先对注册端回复的这个数据包举行处置。

首先验证了第一个字节是否为0x51,接着是读取存储在BlockData中的一个字节和UID。

这里我们回过头看一下注册端最后RegistryImpl_skel,dispatch的部门,由于我们实在并没有剖析它在挪用了api函数后是怎样发送数据包的。我们就以lookup为例:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第60张

首先关注这个var2.getResultStream(true),在这个函数里会写入两个字节和UID。

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第61张

接下来将lookup查询到的var8写入流中。

然后回到挪用RegistryImpl_skel,dispatch的上级方式UnicastServerRef,oldDispatch

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第62张

这里挪用releaseInputStream发送了缓冲的数据。

回过头来,适才剖析到StreamRemoteCall,executeCall读取了BLOCK_DATA中的数据,但还没有读取要害的署理工具,继续看该方式的代码:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第63张

这里之前读到的var1实在是1,以是我们return到上一级。不外也能从这里看到,当读到的var2是2时,是会在这里抛出异常的。

var6.readObject()

重新回到RegistryImpl_Stub,lookup,这里通过了var23 = (Remote)var6.readObject()来获取到lookup查询到的署理工具。

最后把这个var23返回,这就是lookup的全过程了:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第64张

至于finally中的super.ref.done致就是将适才的流释放的操作。

此时的客栈很简练:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第65张

总结

  1. 以客户端定位到注册端并挪用lookup为例,客户端与注册端的通讯流程如下:
    • 客户端发送第一个握手包,注册端回复;
    • 客户端发送第二个包罗ip和端口的包,注册端并不回复;
    • 客户端发送lookup数据包,其内容是字符串的序列化。注册端返回一个序列化的署理工具。
  2. 注册端底层使用UnicastServerRef工具发送请求。与之相对的,客户端使用UnicastRef
  3. 注册端上层获取的工具是RegistryImpl,而客户端上层获取的是RegistryImpl_Stub

4. 客户端—服务端

编写服务端前首先得提供一个接口和一个远程工具。

我自己编写了一个远程挪用接口:

package org.las.remote;

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

public interface IRemoteHelloWorld extends Remote {
    public Object helloWorld(Object word) throws RemoteException;
}

一个远程工具:

package org.las.remote;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloWorldImpl extends UnicastRemoteObject implements IRemoteHelloWorld {

    public RemoteHelloWorldImpl() throws RemoteException{

    }

    public Object helloWorld(Object word) throws RemoteException {
        System.out.println("Hello world..");
        return "las";
    }
}

我的客户端代码:

import org.las.remote.IRemoteHelloWorld;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIServer {
    public static void main(String[] args) throws Exception{
        Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
        IRemoteHelloWorld helloWorld = (IRemoteHelloWorld) registry.lookup("Hello");
        helloWorld.helloWorld("las");
    }
}

在剖析客户端和服务端之前,我想先贴出两者之间发生的流量。

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第66张

红框框住的地方,是客户端在挪用远程方式间隙,执行的有关DGC的操作。同时也可以看到,客户端发送的数据包有些太多了。除去握手包,注重第24和26两个包,基本不是我自己发的(远程挪用的数据包是32、34号)而且数据量比较大。通过将24、26的数据反序列化后会发现,它们也是和DGC有关的。

关于DGC,简朴提一下,全称是distribute garbage collection。实在它的存在也很合理,当客户端获取远程工具时,服务端需要建立一个工具,以供客户端来挪用其上的方式;然则这些工具也并不是永远存在的,它们也需要垃圾网络,这就引出了DGC的观点。然则详细是若何实现的我不太清晰,这也是我剖析RMI源码的一个缘故原由,希望接下来的剖析能让我进一步明白它是若何实现的。

这一次我们先从客户端最先剖析。

在此之前,又先抛出另外一个问题。

新鲜的UnicastRemoteObject

我们知道,一个远程工具,要么得继续UnicastRemoteObject类,要么得通过UnicastRemoteObject,exportObject举行转换:

public class RMIServer {
    public static void main(String[] args) throws Exception{
        System.setSecurityManager(null);
        IRemoteHelloWorld remoteHelloWorld = new RemoteHelloWorldImpl();
        IRemoteHelloWorld remoteHelloWorld2 = new RemoteHelloWorldImpl2();
        Object obj2 = UnicastRemoteObject.exportObject(remoteHelloWorld2,0);
        System.out.println(remoteHelloWorld);
        System.out.println(obj2);
        Registry registry = LocateRegistry.createRegistry(1099);
        registry.bind("Hello", remoteHelloWorld);
        registry.bind("Hello2", (Remote) obj2);
        System.out.println("[*] RMI Server started...");
    }
}

这里我们将两个工具都打印出来看看:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第67张

后者是一个署理工具,前者照样正常的RemoteHelloWorldImpl

然则在客户端看看呢:

public class RMIClient {
    public static void main(String[] args) throws Exception{
        Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
        IRemoteHelloWorld helloWorld = (IRemoteHelloWorld) registry.lookup("Hello");
        IRemoteHelloWorld helloWorld2 = (IRemoteHelloWorld) registry.lookup("Hello2");
        System.out.println(helloWorld);
        System.out.println(helloWorld2);
    }
}

打印效果:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第68张

都是署理工具!

这就新鲜了,在剖析客户端—注册端时,我们讨论了在挪用registry.bind时只是单纯将工具放到registryImpl的成员变量bindings中:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第33张

在客户端lookup时,注册端也只是从这个bindings里将工具取出,并挪用writeObject

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第34张

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第71张

以是问题只可能出在writeObject方式中。

我们跟进var9.writeObject方式,在下面这个地方发现了敏感的函数replaceObject,在进入前我们是RemoteHelloWorldImpl,出来时就是署理工具了:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第72张

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第73张

此时的挪用客栈:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第74张

进入MarshalOutputStream,replaceObject瞧瞧:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第75张

这里的ObjectTable看着怪熟悉的。它在哪个地方似乎泛起过。

实在是在TCPTransport,exportObject中:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第11张

我们之前只跟进了this.listen(),然则在它下面的super.exportObject(var1)里:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第77张

这里!它将Target放到了ObjectTable中。

然则到目前为止,我另有两个疑问:

  • 服务端在什么时刻进入了TCPTransport,exportObject,然后将这个Target放到了objectTable里呢?
  • replaceObject中,挪用Target上的getStub方式获取到的工具和我们在服务端自定义的RemoteHelloWorldImpl有什么关系呢?

由于我们的工具RemoteHelloWorldImpl继续了UnicastRemoteObject类,第一时间想到的就是它的组织函数。我预测也许是在新建RemoteHelloWorldImpl时,挪用的父类无参组织函数做了些事情:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第78张

跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第79张

发现它竟然挪用了exportObject这个静态方式。它是我们建立一个远程工具的第二种方式。继续跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第80张

跟进ㄟ( ▔, ▔ )ㄏ:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第81张

终于到头了。

这里获得了两个信息:

  • 首先,两种导出远程工具的形式最终都市去执行UnicastServerRef,exportObject
  • 其次,接纳UnicastRemoteObject.export(obj, port)获取的远程工具,实在就是UnicastServerRef,exportObject的返回值。

而这个方式,我在客户端—注册端实在已经剖析了。它的返回值就是一个stub,而且在它冗长的挪用链中肯定会执行TCPTransport,exportObject方式。这里又再贴一下UnicastServerRef,exportObject方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第5张

至此,之前的第一个问题解决了。第二个问题:挪用Target上的getStub方式获取到的proxy和我们自己的工具RemoteHelloWorldImpl有什么关系呢?

进入Target的组织函数可以看到:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第83张

var3就是我们刚刚建立的Stub工具。

回到最最最最先,我们新鲜两种建立远程工具的方式最终在客户端获取到的都是同一种类型的问题也解决了:

  • 使用extends UnicaseRemoteObject的方式,在writeObject的时刻,会去获取到响应的Target上的stub工具。
  • 使用UnicastRemoteObject.exportObject(obj,0);的形式,由于它自己返回值就是这个stub,以是会直接被写入。

此时我仍然疑惑,这个stub工具究竟是哪一个类?

跟进到UnicastServerRef,exportObject中的Util.createProxy()方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第84张

之前获取的stub工具是在上面if代码块中的createStub()

而这里则是建立了一个RemoteObjectInvocationHandler的署理工具。

客户端

远程方式挪用

经过了上面的剖析,我们知道了客户端的调试需要从RemoteObjectInvocationHandler,invoke方式最先:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第85张

前面几个if都直接跳过,直接进入到invokeRemoteMethod

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第86张

进入到UnicastRef,invoke方式,这里只贴出较要害的部门:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第87张

new StreamRemoteCall()之前已经跟过一次,就是写入一个版本字节,同时在BLOCK_DATA处写入数据:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第52张

在for循环下的marshalValue()部门,是将客户端执行方式传入的参数一个个写入到流中:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第89张

接下来跟进var7.executeCall(),即StreamRemoteCall,executeCall方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第90张

this.releaseOutputStream();为止,客户端的挪用请求被发送出去。接下来的地方又是老样子,读取首字节,然后获取BLOCK_DATA信息,若是没有抛异常则正常返回(见之前的剖析)。

紧接着在unmarshalValue()方式中,将服务端执行命令后的返回工具举行了反序列化读取到var50中,并作为了UnicastRef,invoke的返回值。

dgc剖析

等等,是不是什么器械漏了?明显另有DGC这些器械啊。它们的流量似乎在RemoteObjectInvocationHandler,invoke之前就发出了。

调试后发现,有关DGC的那段流量,在客户端执行registry.lookup方式时就发出了:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第91张

仔细调试后,定位到执行RegistryImpl_Stub,lookupfinally块中的代码会发出这些流量:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第92张

不停跟进,可以来到StreamRemoteCall,releaseInputStream处:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第93张

registerRefs意味注册引用。看名字有点像是在告诉远端的JVM对工具增添引用的意思

跟进:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第94张

这里获取到的var5类型是List<LiveRef>

跟进DGCClient,registerRefs

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第95张

这里也许有一些难明,然则参考jdk源码的注释则一目了然:

/**
     * Register the LiveRef instances in the supplied list to participate
     * in distributed garbage collection.
     *
     * All of the LiveRefs in the list must be for remote objects at the
     * given endpoint.
     */
    static void registerRefs(Endpoint ep, List<LiveRef> refs) {
        /*
         * Look up the given endpoint and register the refs with it.
         * The retrieved entry may get removed from the global endpoint
         * table before EndpointEntry.registerRefs() is able to acquire
         * its lock; in this event, it returns false, and we loop and
         * try again.
         */
        EndpointEntry epEntry;
        do {
            epEntry = EndpointEntry.lookup(ep);
        } while (!epEntry.registerRefs(refs));
    }

也就是说,每一个Endpoint,它可能有不只一个LiveRef,我们要在这个循环中向Endpoint注册所有这些LiveRef。这里,Endpoint就明白为某个主机上监听在某个端口的历程就行了。

接下来跟进epEntry.registerRefs,即DGCClient,registerRefs(List)

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第96张

跟进DGCClient,makeDirtyCall

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第97张

跟进DGCImpl_Stub,dirty

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第98张

可以看到,在这里发送了dgc请求,而且收到服务端的回复是一个java.rmi.dgc.Lease工具。

而且我们在这里再次看到了“_stub“字眼,再次说明skel和stub的观点不只用于客户端和服务端之间。

这个Lease工具的作用可见官方注释:

/**
 * A lease contains a unique VM identifier and a lease duration. A
 * Lease object is used to request and grant leases to remote object
 * references.
 */

发现它确实有一个成员变量来示意工具的存活时间:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第99张

回过头来,再看一下DGCClient这个工具上官方的注释:

/**
 * DGCClient implements the client-side of the RMI distributed garbage
 * collection system.
 *
 * The external interface to DGCClient is the "registerRefs" method.
 * When a LiveRef to a remote object enters the VM, it needs to be
 * registered with the DGCClient to participate in distributed garbage
 * collection.
 *
 * When the first LiveRef to a particular remote object is registered,
 * a "dirty" call is made to the server-side distributed garbage
 * collector for the remote object, which returns a lease guaranteeing
 * that the server-side DGC will not collect the remote object for a
 * certain period of time.  While LiveRef instances to remote objects
 * on a particular server exist, the DGCClient periodically sends more
 * "dirty" calls to renew its lease.
 *
 * The DGCClient tracks the local reachability of registered LiveRef
 * instances (using phantom references).  When the LiveRef instance
 * for a particular remote object becomes garbage collected locally,
 * a "clean" call is made to the server-side distributed garbage
 * collector, indicating that the server no longer needs to keep the
 * remote object alive for this client.
 *
 * @see java.rmi.dgc.DGC, sun.rmi.transport.DGCImpl
 *
 * @author  Ann Wollrath
 * @author  Peter Jones
 */

这里看到,自挪用StreamRemoteCall,releaseInputStream中的this.in.RegisterRefs以来,客户端所作的事情,确实是向服务端注册每一个LiveRef,而且获取到服务端返回的Lease,来告诉服务端短时间内不要接纳这些工具。至于像注释说的,租约lease到期后需要再次发送dirty call的操作,就不再跟进了。

服务端

我们在客户端—注册端一节,调试LocateRegistry,createRegistry时曾跟进了UnicastServerRef,exportObject方式。它的挪用栈会在某个地方执行this.listen()方式监听在某个端口接受客户端的请求;

回到客户端—服务端,由于前面剖析过,建立一个远程工具无论怎样都市挪用UnicastRemoteObject,exportObject方式:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第81张

在这里也挪用了UnicastServerRef,exportObject方式。

以是服务端和注册端一样都通过了UnicastServerRef工具来开放服务。这里就不进一步跟进了。

需要强调的是UnicastServerRef,dispatch方式,我前面也提到过:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第101张

在远程方式挪用时,它是不会进入这个if分支的,而是会继续向下执行。

它首先会从返回数据中读取一个数据类型为Long的变量:

var4 = var39.readLong();

这个long变量实在是客户端想要挪用方式的哈希,当在this.hashToMethod_Map获取不到时会报错:

usdt充值接口(caibao.it):深入学习rmi事情原理 安全技术 WEB安全 第102张

在学习使用反序列化攻击rmi服务端时,若是在客户端自己魔改了远程工具的接口方式(好比参数类型原本在服务端是java.lang.String,但在客户端修改为java.lang.Object),此时需要修改这个哈希值才气正常攻击。

总结

  • dgc流程:
    1. 客户端通过lookup获取到一个工具后,会向服务端提议一次dirty call,以通知服务端短时间内不要接纳该工具;
    2. 服务端返回给客户端一个lease,该工具告诉了客户端接下来多久的时间内该工具是有用的。若是客户端在时间到期后还需要使用该工具,则需要继续挪用dirty call
    3. DGCClient会跟踪每一个liveRef,当他们在客户端已经不再有用后,就会提议clear call告诉服务端可以接纳有关工具了。
  • 无论是rmi注册端照样服务端,它们都通过UnicastServerRef,exportObject开启指定端口上的服务,最终都市进入TCPTransport,handleMessages中的循环来监听输入流,而且最后又都市使用UnicastServerRef,dispatch来挪用注册端或者服务端的功效。

参考链接

  1. 针对RMI服务的九重攻击
  2. Java平安-RMI-学习总结
  3. DGCClient源码


Allbet声明:该文看法仅代表作者自己,与www.allbetgame.us无关。转载请注明:usdt充值接口(caibao.it):深入学习rmi事情原理
发布评论

分享到:

约搏棋牌:苹果手机玩王者好在哪,为何主播都爱用?
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。