0x00 前言
仅作为笔记,对之前的内容进行补充
Registry
Registry是可以单独创建的
LocateRegistry.createRegistry(1099);
实例化RegistryImpl对象
public static Registry createRegistry(int port) throws RemoteException {
return new RegistryImpl(port);
}
创建LiveRef并且将LiveRef封装为UnicastServerRef,然后setup
public RegistryImpl(int var1) throws RemoteException {
//创建 LiveRef
LiveRef var2 = new LiveRef(id, var1);
//UnicastServerRef封装LiveRef
this.setup(new UnicastServerRef(var2));
}
这里通过exportObject,主要是两个目的,一个是开启soket监听,还有一个就是注册远程类以及创建DGCI
private void setup(UnicastServerRef var1) throws RemoteException {
this.ref = var1;
//调用UnicastServerRef 的exportObject
var1.exportObject(this, (Object)null, true);
}
RegistryImpl代理,创建target对象
public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException {
Class var4 = var1.getClass();
Remote var5;
try {
//创建sun.rmi.registry.RegistryImpl代理
var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);
} catch (IllegalArgumentException var7) {
throw new ExportException("remote object implements illegal remote interface", var7);
}
//检测接口Remote
if (var5 instanceof RemoteStub) {
this.setSkeleton(var1);
}
//创建target对象
Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);
this.ref.exportObject(var6);
this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4);
return var5;
}
创建代理
public static Remote createProxy(Class<?> var0, RemoteRef var1, boolean var2) throws StubNotFoundException {
Class var3;
try {
//获取对应的class,会去校验是否是Remote的子类
var3 = getRemoteClass(var0);
} catch (ClassNotFoundException var9) {
throw new StubNotFoundException("object does not implement a remote interface: " + var0.getName());
}
//检测withoutStubs中是否包含由类名创建的_Stub组成的内容,
//如果有则返回false,没有则创建并且返回false
if (var2 || !ignoreStubClasses && stubClassExists(var3)) {
return createStub(var3, var1);
} else {
ClassLoader var4 = var0.getClassLoader();
Class[] var5 = getRemoteInterfaces(var0);
RemoteObjectInvocationHandler var6 = new RemoteObjectInvocationHandler(var1);
try {
return (Remote)Proxy.newProxyInstance(var4, var5, var6);
} catch (IllegalArgumentException var8) {
throw new StubNotFoundException("unable to create proxy", var8);
}
}
}
private static Class<?> getRemoteClass(Class<?> var0) throws ClassNotFoundException {
while(var0 != null) {
// 反射获取接口,create的时候为:sun.rmi.registry.RegistryImpl
Class[] var1 = var0.getInterfaces();
for(int var2 = var1.length - 1; var2 >= 0; --var2) {
//判断是否是Remote.class的子类,是的话直接返回
if (Remote.class.isAssignableFrom(var1[var2])) {
return var0;
}
}
var0 = var0.getSuperclass();
}
throw new ClassNotFoundException("class does not implement java.rmi.Remote");
}
private static RemoteStub createStub(Class<?> var0, RemoteRef var1) throws StubNotFoundException {
//类名+_Stub
String var2 = var0.getName() + "_Stub";
try {
//调用输入类的构造方法
Class var3 = Class.forName(var2, false, var0.getClassLoader());
Constructor var4 = var3.getConstructor(stubConsParamTypes);
return (RemoteStub)var4.newInstance(var1);
} catch (ClassNotFoundException var5) {
throw new StubNotFoundException("Stub class not found: " + var2, var5);
} catch (NoSuchMethodException var6) {
throw new StubNotFoundException("Stub class missing constructor: " + var2, var6);
} catch (InstantiationException var7) {
throw new StubNotFoundException("Can't create instance of stub class: " + var2, var7);
} catch (IllegalAccessException var8) {
throw new StubNotFoundException("Stub class constructor not public: " + var2, var8);
} catch (InvocationTargetException var9) {
throw new StubNotFoundException("Exception creating instance of stub class: " + var2, var9);
} catch (ClassCastException var10) {
throw new StubNotFoundException("Stub class not instance of RemoteStub: " + var2, var10);
}
}
设置setSkeleton,同时会创建skel
public void setSkeleton(Remote var1) throws RemoteException {
//检测withoutSkeletons是否存在
if (!withoutSkeletons.containsKey(var1.getClass())) {
try {
//不存在则创建类_Skel
this.skel = Util.createSkeleton(var1);
} catch (SkeletonNotFoundException var3) {
withoutSkeletons.put(var1.getClass(), (Object)null);
}
}
}
然后通过exportObject开启socket,并且绑定远程对象,至此,Registry启动完成
public void exportObject(Target var1) throws RemoteException {
synchronized(this) {
//检测socket是否开启
this.listen();
++this.exportCount;
}
boolean var2 = false;
boolean var12 = false;
try {
var12 = true;
//将target绑定到ObjectTable中去
super.exportObject(var1);
var2 = true;
var12 = false;
} finally {
if (var12) {
if (!var2) {
synchronized(this) {
this.decrementExportCount();
}
}
}
}
if (!var2) {
synchronized(this) {
this.decrementExportCount();
}
}
}
DGCI
在创建Registry的时候,生成Target,会同时创建DGCI分布式垃圾回收。
DGCImpl.class
rt.jar!\sun\rmi\transport\DGCImpl.class
在创建的DGCImpl_Skel(服务端)中,通过dispatch触发反序列化
server
通过stub绑定,进行序列化
然后通过skel进行反序列化
补充知识
RMI
RMI(Remote Method Invocation)是Java中远程调用机制的实现,其目的是在分布式系统中的Java对象之间传递消息和方法调用。通过RMI,可以实现在不同的Java虚拟机(JVM)之间交互和通信,就像调用本地的Java对象一样。
RMI的核心机制是Java远程对象(Java Remote Object)。Java远程对象是指实现了Java RMI接口的Java对象,其可以通过RMI框架进行序列化、传输和反序列化等操作,实现跨网络的远程调用。RMI提供了远程对象的注册、查找、绑定、解除绑定等功能,使得客户端可以通过远程对象进行远程调用操作。
RMI优点包括:
- RMI可以将Java对象直接暴露给远程访问,无需任何
RMI三端
RMI指的是Java远程方法调用,它采用了客户机/服务器架构来支持分布式应用程序的开发。RMI由三个组成部分组成,分别是:
-
远程接口:远程接口是客户端和服务器之间进行通信的一组方法和参数,它定义了客户端和服务器之间交互的规范。
-
远程对象:远程对象是实现了远程接口的Java对象。当客户端调用一个远程对象时,它实际上是在调用服务器上的对象。
-
远程对象注册表:远程对象注册表是在服务器上运行的中间件,它充当了客户端和服务器之间的桥梁。客户端可以向注册表注册远程对象,并从注册表检索这些对象。
RMI 反序列化
RMI(Remote Method Invocation)是一种 Java 远程调用机制,它提供了一种方便的方式来调用远程主机中的 Java 对象上的方法。其中一项关键功能是可以在网络上传输可序列化的 Java 对象。而 RMI 反序列化漏洞,指的是攻击者通过构建恶意序列化数据来触发远程主机中的 RMI 应用程序的漏洞,使其执行攻击者所期望的代码。
由于 Java 中的对象可以被序列化并在网络上进行传输,因此攻击者可以构建恶意的序列化数据并将其发送到 RMI 应用程序。当这些数据被传输到受害者主机并进行反序列化时,攻击者可以在远程主机上执行代码,造成任意的攻击效果,比如执行远程命令、获取敏感信息等。
为了防止 RMI 反序列化漏洞,可以采取以下措施:
-
避免使用不必要的远程调用
-
对输入进行有效的过滤和验证
-
使用安全的序列化协议
-
对反序列化代码进行安全审计和修复
-
限制 RMI 应用程序的网络访问权限
-
升级 Java 运行环境和 RMI 库至最新版本,并启用安全配置。
RMI反序列化限制
在RMI中,服务器和客户端之间通过Java对象的序列化和反序列化来交换数据。反序列化过程将二进制数据转换为Java对象,这可能会导致安全漏洞。因此,为了保护系统的安全,RMI实现了反序列化限制。
RMI反序列化限制包括以下两个方面:
-
类型限制:在反序列化过程中,只有预定义的安全类可以被反序列化。这些安全类由默认安全管理器所定义,也可以由开发人员自定义。
-
对象图限制:在反序列化过程中,对象图必须是有限的,即不能包含对不受信任类的引用。这是通过在反序列化时验证类定义的方式实现的。
这些反序列化限制的主要目的是防止恶意攻击者利用反序列化来执行任意代码或创建任意对象。因此,开发人员应该遵循最佳实践,如避免反序列化不受信任的数据和使用最新的Java版本等,以确保系统的安全性。