1098/1099 - Pentesting Java RMI

Basic Information

The Java Remote Method Invocation, or Java RMI, is a mechanism that allows an object that exists in one Java virtual machine to access and call methods that are contained in another Java virtual machine; This is basically the same thing as a remote procedure call, but in an object-oriented paradigm instead of a procedural one, which allows for communication between Java programs that are not in the same address space.

One of the major advantages of RMI is the ability for remote objects to load new classes that aren't explicitly defined already, extending the behavior and functionality of an application. From here.

Default port: 1099, 1098

1099/tcp open rmiregistry syn-ack
1099/tcp open java-rmi Java RMI


(Example taken from here) The following classes implement a simple client-server program using RMI that displays a message.

RmiServer class — listens to RMI requests and implements the interface which is used by the client to invoke remote methods.

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.*;
public class RmiServer extends UnicastRemoteObject implements RmiServerIntf {
public static final String MESSAGE = "Hello World";
public RmiServer() throws RemoteException {
super(0); // required to avoid the 'rmic' step, see below
public String getMessage() {
return MESSAGE;
public static void main(String args[]) throws Exception {
System.out.println("RMI server started");
try { //special exception handler for registry creation
System.out.println("java RMI registry created.");
} catch (RemoteException e) {
//do nothing, error means registry already exists
System.out.println("java RMI registry already exists.");
//Instantiate RmiServer
RmiServer server = new RmiServer();
// Bind this object instance to the name "RmiServer"
Naming.rebind("//localhost/RmiServer", server);
System.out.println("PeerServer bound in registry");

RmiServerIntf interface — defines the interface that is used by the client and implemented by the server.

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RmiServerIntf extends Remote {
String getMessage() throws RemoteException;

RmiClient class — this is the client which gets the reference (a proxy) to the remote object living on the server and invokes its method to get a message. If the server object implemented instead of java.rmi.Remote, it would be serialized and passed to the client as a value.[2]

import java.rmi.Naming;
public class RmiClient {
public static void main(String args[]) throws Exception {
RmiServerIntf server = (RmiServerIntf)Naming.lookup("//localhost/RmiServer");


Based on the fact that arbitrary java is being treated in a different Java VM, this may allow an attacker to deserialize a payload in this Java instance and execute arbitrary code. The default configuration of rmiregistryallows loading classes from remote URLs, which can lead to remote code execution.

Basically this service could allow you to execute code.

msf> use auxiliary/scanner/misc/java_rmi_server
msf> use auxiliary/gather/java_rmi_registry
nmap -sV --script "rmi-dumpregistry or rmi-vuln-classloader" -p <PORT> <IP>

RMI methods enumeration to explore and try to find RCE vulnerabilities. to enumerate and attack allows an easy exploitation of insecure configured JMX services (I tried and It gave me Error: Can't connect to remote service let me know if you know how to fix this issue).

Reverse Shell


msf> use exploit/multi/misc/java_rmi_server


  • port:1099 java