RMI反序列化攻击学习(1)
RMI反序列化流程分析学习
这篇文章主要是较为详细的分析学习一下RMi运行的源码
可以先看下这个视频基本就了解了大致的过程
【Java反序列化RMI专题-没有人比我更懂RMI】https://www.bilibili.com/video/BV1L3411a7ax?p=10&vd_source=2884b80d333f3bfc8048b360e6195550
然后把这篇文章的图借来分析,Java RMI 攻击由浅入深 | 素十八,主要是分析下这9个过程的源码运行


RMI的简单了解
也不说太多,网上很多
RMI应用程序通常包含两个独立的程序,一个服务器和一个客户端。典型的服务器程序创建一些远程对象,使对这些对象的引用可访问,并等待客户端调用这些对象上的方法。
典型的客户端程序获取对服务器上一个或多个远程对象的远程引用,然后调用它们上的方法。RMI提供了服务器和客户端通信和来回传递信息的机制。 这样的应用程序有时被称为分布式对象应用程序。
执行流程:
-
首先开启注册服务
-
RMI创建实现接口的类的对象,并在注册服务中注册
-
客户端从注册服务调用接口里的方法
代码实例
客户端
public class RMIClient {
public static void main(String[] args) throws Exception {
//客户端获取注册中心
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
//去注册中心查找remoteObj
IRemoteObj remoteObj = (IRemoteObj) registry.lookup("remoteObj");
remoteObj.sayHello("hello");
}
}
public interface IRemoteObj extends Remote {
//sayHello就是客户端要调用的方法
public String sayHello(String test) throws RemoteException;
}
服务端
public interface IRemoteObj extends Remote {
//sayHello就是客户端要调用的方法
public String sayHello(String obj) throws Exception;
}
//服务端的实现类,最后调用是服务端的实现类 UnicastRemoteObject通用的远程对象用于绑定到RMI服务
public class RemoteObjImpl extends UnicastRemoteObject implements IRemoteObj {
public RemoteObjImpl() throws RemoteException {}
@Override
public String sayHello(String obj) throws Exception {
System.out.println(obj);
return "Hello World";
}
}
public class RMIServer {
public static void main(String[] args) throws RemoteException, AlreadyBoundException {
RemoteObjImpl remoteObj = new RemoteObjImpl();
Registry registry = LocateRegistry.createRegistry(1099);
registry.bind("remoteObj",remoteObj);
}
}
启动结果就是在服务端打印hello,返回给客户端hello World(可打印)
接下来分析这9过程

1.创建远程对象
这一步呢主要就是暴露我们需要给客户端提供的服务

所以如果你没有继承UnicastRemoteObject的话,得自己通过这个方法发布

再调用重载方法

UnicastServerRef,存入了LiveRef

LiveRef中存入了TCPEndpoint通过调用静态方法,TCPEndpoint里面是处理tcp通信的流程,可以说是一个代理,专门处理网络请求


所以回到这里,其实就是完成了处理网络请求的部分

里面调用UnicastRemoteObject.exportObject

创建了动态代理

createProxy逻辑

stubClassExists逻辑,显然是找不到我们的RemoteObjImpl(自己实现的类),而在后面创建registryImpl_Stub是存在的,会调用createstub

createStub,也就是说java里面存在的会直接反射实例化,然后回到之前的exportObject


发布会一直到TCPTransport.exportObject,调用listen()开启监听


然后调用Transport.exportObject,将target放入静态表objTable中,第一个过程结束

2.向注册中心注册远程对象
也就是这两步
Registry registry = LocateRegistry.createRegistry(1099);
registry.bind("remoteObj",remoteObj);
首先获得注册中心,基本上和创建远程对象的步骤差不多,端口固定,多的不赘述了。看看不同的地方

上面也说了,RegistryImpl是自带的,然后此处if这里为true与上面不一致,所以会创建一个骨架,和创建存根逻辑基本一致,这个骨架的作用是分发服务,后面遇到了再详细解释,然后就结束了,和创建服务端差不多

接着就是绑定服务给注册中心,bindings是一个hash表,然后把名称和实现类放入即可

3.访问注册中心查找远程对象
接下来就是客户端的操作了
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
IRemoteObj remoteObj = (IRemoteObj) registry.lookup("remoteObj");
remoteObj.sayHello("hello");
和之前的一模一样不赘述了,所以其实这一步没有真正的访问注册中心,在本地创建了stub,用这个stub去和注册中心连接

调试第二步,lookup查找,首先通过newCall进行网络连接,然后序列化写入了名称给注册中心,注册中心当然会反序列化接受,这就成了一个攻击点,然后调用了invoke方法,invoke主要是调用了,executeCall

前面有一段关于DGC的处理,DGC(分布式垃圾回收)的核心功能管理远程对象的生命周期,前面也就是进行了一个释放与当前输出流相关的系统资源

而后发生返回类型为如图时,会把类型反序列化出来,这也就是导致可以攻击的一点,客户端通过注册中心
然后通过反序列化读了注册中心传入的对象,可导致注册中心攻击客户端

注册中心返回了一个动态代理,也就是第一步创建远程对象创建的存根stub接着看注册中心如何查找返回

4.返回远程对象的存根
这个注册中心的断点应该打?可以通过我们之前监听listen()创建线程一直找,然后看线程的run方法,这不重要


一直到UnicastServerRef#dispatch,然后调用oldDispatch,判断有无骨架,只有注册中心拥有,是这里是调用了oldDispatch方法

oldDispatch会调用RegistryImpl_Skel#dispatch ,然后对应0->bind,1->list 2->lookup 3->rebind 4->unbind,每个方法都是反序列化读的数据都能造成攻击,也就是服务端和客户端都能对注册中心攻击。反序列化的是"remoteObj",然后lookup

从表里找即可,返回的是动态代理,也就是第三步结尾的代理对象就是这样来的。

5.调用service,不经过registry,直接与服务端通信
也就是这一步的流程
remoteObj.sayHello("hello");
调用动态代理的invoke.调用invokeRemoteMethod

调用invoke,注意第四个参数传入method的hash值,然后服务端再通过hash值找对应的方法,所以这里我们可以通故修改hash值绕过服务端的一些校验完成攻击,这个之后再说.
然后通过marshalValue序列化参数值,unmarshalValue反序列化返回值,中间还会调用executeCall,刚刚说过也会导致攻击

服务端,同样也是通过UnicastServerRef#dispatch方法,和请求注册中心前面的通信是一致的,不一样是if判断为false,所以往后进行调用服务端的操作

从hashToMethod_Map中拿方法,然后unmarshalValue,反序列化拿参数值

通过invoke调用服务端的方法,然后把marshalValue进行了序列化返回值,这里导致服务端与客户端互相攻击,整个流程就分析完了

结合这张图就能很清晰的理解整个流程了,接下来就是学习攻击手法了

参考:
https://www.anquanke.com/post/id/259059#h3-11
https://su18.org/post/rmi-attack/#3-remoteobject
https://www.cnblogs.com/R0ser1/p/16757433.html#通过rasp-bypass原理object参数

浙公网安备 33010602011771号