栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java代码审计——RMI浅析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java代码审计——RMI浅析

0x00 前言

简单的概述一下全过程:

首先分为三端:
- registry端
- server端
- client端

registry作为一个中间人,
server端使用bind或者rebind和registry进行交互,在交互过程中使用tcp协议进行通信,并且在invoke方法时,进行序列化和反序列化
client端使用look和registry进行交互,通过在invoke方法中进行序列化和反序列化

实际上,server和client是没有进行直接交互的。

server 过程

全部的server内容:

public class Server {


    public static void main(String args[]) throws Exception{
        //以1099作为LocateRegistry接收客户端请求的端口,并注册服务的映射关系
        Registry registry= LocateRegistry.createRegistry(1099);
        IOperation iOperation=new OperationImpl();
        Naming.rebind("rmi://127.0.0.1:1099/Operation",iOperation);
        System.out.println("service running...");
    }
}

server在启动后会进行顺序启动:

1.开启createRegistry

首先是createRegistry

  • javarmiregistryLocateRegistry.java

    跟进 RegistryImpl
    jetbrains://idea/navigate/reference?project=rmi_demo&path=D:/jdk1.8.0_152/jre/lib/rt.jar!/sun/rmi/registry/RegistryImpl.class
 public RegistryImpl(final int var1) throws RemoteException {
        this.bindings = new Hashtable(101);
        //判断端口是否是1099,也就是默认端口
        if (var1 == 1099 && System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction() {
                    public Void run() throws RemoteException {
                        LiveRef var1x = new LiveRef(RegistryImpl.id, var1);
                        RegistryImpl.this.setup(new UnicastServerRef(var1x, (var0) -> {
                            return RegistryImpl.registryFilter(var0);
                        }));
                        return null;
                    }
                }, (AccessControlContext)null, new SocketPermission("localhost:" + var1, "listen,accept"));
            } catch (PrivilegedActionException var3) {
                throw (RemoteException)var3.getException();
            }
        } else {
        	//创建LiveRef对象
            LiveRef var2 = new LiveRef(id, var1);
            //关键点:
            this.setup(new UnicastServerRef(var2, RegistryImpl::registryFilter));
        }
    }

接着来看setup

jetbrains://idea/navigate/reference?project=rmi_demo&path=D:/jdk1.8.0_152/jre/lib/rt.jar!/sun/rmi/registry/RegistryImpl.class

跟进exportObject

public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException {
        Class var4 = var1.getClass();

        Remote var5;
        try {
        	//创建了一个Registry_stub
            var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);
        } catch (IllegalArgumentException var7) {
            throw new ExportException("remote object implements illegal remote interface", var7);
        }

        if (var5 instanceof RemoteStub) {
        	//将输入的配置和stub绑定
            this.setSkeleton(var1);
        }

        Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);
        //以当前配置,开启一条线程,监听ip+port
        this.ref.exportObject(var6);
        this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4);
        return var5;
    }
2.绑定registry

首先这里是rebind,不管是bind还是rebind还是look,都要触发的是newCall

    public void rebind(String var1, Remote var2) throws AccessException, RemoteException {
        try {
            RemoteCall var3 = this.ref.newCall(this, operations, 3, 4905912898345647071L);

            try {
                ObjectOutput var4 = var3.getOutputStream();
                var4.writeObject(var1);
                var4.writeObject(var2);
            } catch (IOException var5) {
                throw new MarshalException("error marshalling arguments", var5);
            }
		//在invoke这里进行数据传递
            this.ref.invoke(var3);
            this.ref.done(var3);
        } catch (RuntimeException var6) {
            throw var6;
        } catch (RemoteException var7) {
            throw var7;
        } catch (Exception var8) {
            throw new UnexpectedException("undeclared checked exception", var8);
        }
    }
newCall

newCall实际上就是创建了一个交互连接,没有进行实际数据传递。

    public RemoteCall newCall(RemoteObject var1, Operation[] var2, int var3, long var4) throws RemoteException {
        clientRefLog.log(Log.BRIEF, "get connection");
        //建立了一个tcp的连接
        Connection var6 = this.ref.getChannel().newConnection();

        try {
            clientRefLog.log(Log.VERBOSE, "create call context");
            if (clientCallLog.isLoggable(Log.VERBOSE)) {
                this.logClientCall(var1, var2[var3]);
            }
			//获取远程连接
            StreamRemoteCall var7 = new StreamRemoteCall(var6, this.ref.getObjID(), var3, var4);

            try {
            	//拿到数据
                this.marshalCustomCallData(var7.getOutputStream());
            } catch (IOException var9) {
                throw new MarshalException("error marshaling custom call data");
            }

            return var7;
        } catch (RemoteException var10) {
            this.ref.getChannel().free(var6, false);
            throw var10;
        }
    }
StreamRemoteCall中进行判断

jetbrains://idea/navigate/reference?project=rmi_demo&path=D:/jdk1.8.0_152/jre/lib/rt.jar!/sun/rmi/transport/StreamRemoteCall.class

在这里进入2之后就会进行readObject

Client 过程
public class Client {
    public static void main(String args[]) throws Exception{
        IOperation iOperation= (IOperation) Naming.lookup("rmi://127.0.0.1:1099/Operation");
        System.out.println(iOperation.add(1,1));
    }
}

这里首先进入的newcall,newcall和rebind的一致。流程也大差不差。 简单的理解就是,首先和registry进行交互,然后确定好之后发送序列化数据,然后就会收到registry的数据,然后当client数据对存在问题的代码进行了反序列化漏洞就会触发。


各种福利可咨询:570714949

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/697460.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号