0x01の基本概念
RMIの完全な名前はリモートメソッド呼び出しです。つまり、リモートメソッド呼び出しです。どのように実装するのですか。リモートサーバーは、特定のクラスとメソッドを提供します。ローカルは、何らかの方法でリモートクラスのプロキシを取得し、このプロキシを介してリモートオブジェクトのメソッドを呼び出します。メソッドのパラメータは、シリアル化と逆シリアル化によって渡されるため、1.サーバーオブジェクトがメソッドを提供する限り、このメソッドはオブジェクト型パラメーターを受け取ります。2。リモートサーバーのクラスパスに使用可能なポップチェーンがあり、クライアントでこのメソッドを呼び出して渡すことができます。 RMIサービスを攻撃するために慎重に作成されたオブジェクトアプローチ。
0x02実装メカニズム
上記のように、ローカルは何らかの方法でリモートオブジェクトのプロキシを取得するので、具体的な実装メカニズムは何ですか。RMIモードのクライアントとサーバーに加えて、レジストリも使用されます。
サーバ | レジストリ | クライアント |
---|---|---|
特定のリモートオブジェクトを提供する | リモートオブジェクトの場所(IP、ポート、識別子)を格納するレジストリ | リモートオブジェクトのユーザー |
その中でも、サーバーとレジストリは、同じサーバーに実装することも、別のサーバーにデプロイすることもできます。完全なRMIプロセスは、おおまかに次のように説明できます。
- レジストリが最初に起動し、ポート(通常は1099)で待機します
- サーバーはリモートオブジェクトをレジストリに登録します
- クライアントはレジストリからリモートオブジェクトのプロキシを取得し(このプロキシはネットワーク内のリモートオブジェクトの特定の場所(ip、ポート、識別子)を知っています)、クライアントはこのプロキシを介してリモートメソッドを呼び出します。サーバーにもプロキシがあり、サーバー側のプロキシはクライアントによって呼び出されたメソッドとパラメーターを受信した後、エージェントは対応するメソッドを実行し、ネットワーク経由でクライアントに結果を返します。
2つの写真は1000語に相当します。
全体的なプロセス:
ps:写真のスタブはクライアントプロキシで、スケルトンはサーバープロキシです。外国人から与えられた英語の名前が本当にわかりません〜
リモートメソッド呼び出しの通信モード:
私のような誰かがなぜこの登録フォームが必要なのかについて考えたのだろうか?
0x03コードの実装
一般的なプロセスはすでにわかっているので、コードを使用して上記のプロセスを実装する方法は?自分でプロジェクトを作成してみましょう。プロジェクトの構造は次のとおりです。
1.まず、インターフェースHelloを作成します。
package model;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
public String welcome(String name) throws RemoteException;
}
2.このインターフェイスに基づいて、クラスHelloimplを実装します。
package model.impl;
import model.Hello;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Helloimpl extends UnicastRemoteObject implements Hello {
public Helloimpl() throws RemoteException {
}
@Override
public String welcome(String name) throws RemoteException {
return "Hello, "+name;
}
}
3.サーバーを作成します。サーバーはレジストリを作成し、クライアントが必要とするオブジェクトを登録します
package server;
import model.Hello;
import model.impl.Helloimpl;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Server {
public static void main(String[] args) throws RemoteException{
// 创建对象
Hello hello = new Helloimpl();
// 创建注册表
Registry registry = LocateRegistry.createRegistry(1099);
// 绑定对象到注册表,并给他取名为hello
registry.rebind("hello", hello);
}
}
4.クライアントがリモートオブジェクトを呼び出す
package client;
import model.Hello;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) throws RemoteException, NotBoundException {
// 获取到注册表的代理
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
// 利用注册表的代理去查询远程注册表中名为hello的对象
Hello hello = (Hello) registry.lookup("hello");
// 调用远程方法
System.out.println(hello.welcome("axin"));
}
}
最初にサーバーを起動します。クライアントを起動すると、クライアントはリモートメソッドを正常に実行し、返されたデータを取得します。
コードを書くときに注意すべきことがいくつかあります。
- インターフェースはRemoteインターフェースを統合する必要があり、メソッドはRemoteExceptionエラーをスローする必要があります
- インターフェイスの実装クラスはUnicastRemoteObjectを継承する必要があり、同じメソッドがRemoteExceptionエラーをスローする必要があります
- リモートメソッドがパラメーターを渡す必要がある場合は、パラメーターがシリアル化可能であることを確認する必要があります。ここで文字列を渡すだけです。文字列はシリアル化可能です。渡されたパラメーターがカスタムオブジェクトの場合、オブジェクトはSerilizableインターフェイスを実装する必要があります
ここではサーバーとクライアントが同じマシン上に実装されているため、比較的単純に見えます。サーバーとクライアントが同じホスト上にない場合は、呼び出されたリモートオブジェクトによって実装されるインターフェースがクライアント上にあることを確認する必要がありますどちらもサーバー側に存在します!
0x04その他
これで、rmiのデシリアライゼーションの脆弱性について学ぶ必要があるため、当面はほぼ完了です。rmiの基礎となるコードの実装に興味がある場合は、jdkのソースコードをもう一度読むと、rmi〜の理解が深まります。
ソースレベルからのrmiの実装を分析する記事を載せてください:https://xz.aliyun.com/t/2223
記事を読みながら、練習を組み合わせることをお勧めします
私の公式アカウントに従って、一緒にプレイしてください