Java Remote Method Invocation, o Java RMI, es un mecanismo RPC orientado a objetos que permite a un objeto ubicado en una máquina virtual Java llamar a métodos en un objeto ubicado en otra máquina virtual Java. Esto permite a los desarrolladores escribir aplicaciones distribuidas utilizando un paradigma orientado a objetos. Una breve introducción a Java RMI desde una perspectiva ofensiva se puede encontrar en esta charla de blackhat.
Puerto por defecto: 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
Usualmente, solo los componentes predeterminados de Java RMI (el RMI Registry y el Activation System) están vinculados a puertos comunes. Los remote objects que implementan la aplicación RMI real suelen estar vinculados a puertos aleatorios, como se muestra en la salida anterior.
nmap a veces tiene problemas para identificar servicios RMI protegidos por SSL. Si te encuentras con un servicio ssl desconocido en un puerto RMI común, deberías investigar más a fondo.
Componentes RMI
Para ponerlo en términos simples, Java RMI permite a un desarrollador hacer un Java object disponible en la red. Esto abre un puerto TCP donde los clientes pueden conectarse y llamar a métodos en el objeto correspondiente. A pesar de que esto suena simple, hay varios desafíos que Java RMI necesita resolver:
Para despachar una llamada a un método a través de Java RMI, los clientes necesitan conocer la dirección IP, el puerto de escucha, la clase o interfaz implementada y el ObjID del objeto objetivo (el ObjID es un identificador único y aleatorio que se crea cuando el objeto se hace disponible en la red. Es necesario porque Java RMI permite que múltiples objetos escuchen en el mismo puerto TCP).
Los clientes remotos pueden asignar recursos en el servidor invocando métodos en el objeto expuesto. La Java virtual machine necesita rastrear cuáles de estos recursos aún están en uso y cuáles pueden ser recolectados como basura.
El primer desafío se resuelve mediante el RMI registry, que es básicamente un servicio de nombres para Java RMI. El RMI registry en sí también es un RMI service, pero la interfaz implementada y el ObjID son fijos y conocidos por todos los clientes RMI. Esto permite a los clientes RMI consumir el RMI registry solo conociendo el puerto TCP correspondiente.
Cuando los desarrolladores quieren hacer sus Java objects disponibles dentro de la red, generalmente los vinculan a un RMI registry. El registry almacena toda la información requerida para conectarse al objeto (dirección IP, puerto de escucha, clase o interfaz implementada y el valor ObjID) y la hace disponible bajo un nombre legible por humanos (el bound name). Los clientes que desean consumir el RMI service preguntan al RMI registry por el bound name correspondiente y el registro devuelve toda la información necesaria para conectarse. Así, la situación es básicamente la misma que con un servicio DNS ordinario. La siguiente lista muestra un pequeño ejemplo:
importjava.rmi.registry.Registry;importjava.rmi.registry.LocateRegistry;importlab.example.rmi.interfaces.RemoteService;publicclassExampleClient {privatestaticfinalString remoteHost ="172.17.0.2";privatestaticfinalString boundName ="remote-service";publicstaticvoidmain(String[] args){try {Registry registry =LocateRegistry.getRegistry(remoteHost); // Connect to the RMI registryRemoteService ref = (RemoteService)registry.lookup(boundName); // Lookup the desired bound nameString response =ref.remoteMethod(); // Call a remote method} catch( Exception e) {e.printStackTrace();}}}
El segundo de los desafíos mencionados anteriormente se resuelve mediante el Distributed Garbage Collector (DGC). Este es otro RMI service con un valor de ObjID bien conocido y está disponible en prácticamente cada RMI endpoint. Cuando un RMI client comienza a usar un RMI service, envía una información al DGC de que el remote object correspondiente está en uso. El DGC puede entonces rastrear el conteo de referencias y es capaz de limpiar objetos no utilizados.
Junto con el Activation System obsoleto, estos son los tres componentes predeterminados de Java RMI:
El RMI Registry (ObjID = 0)
El Activation System (ObjID = 1)
El Distributed Garbage Collector (ObjID = 2)
Los componentes predeterminados de Java RMI han sido vectores de ataque conocidos durante bastante tiempo y existen múltiples vulnerabilidades en versiones obsoletas de Java. Desde la perspectiva de un atacante, estos componentes predeterminados son interesantes, porque implementan clases / interfaces conocidas y es fácilmente posible interactuar con ellos. Esta situación es diferente para los RMI services personalizados. Para llamar a un método en un remote object, necesitas conocer la firma del método correspondiente de antemano. Sin conocer una firma de método existente, no hay forma de comunicarse con un RMI service.
RMI Enumeration
remote-method-guesser es un escáner de vulnerabilidades de Java RMI que es capaz de identificar automáticamente vulnerabilidades comunes de RMI. Siempre que identifiques un RMI endpoint, deberías intentarlo:
$ 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
La salida de la acción de enumeración se explica con más detalle en las páginas de documentación del proyecto. Dependiendo del resultado, deberías intentar verificar las vulnerabilidades identificadas.
Los valores ObjID mostrados por remote-method-guesser pueden ser utilizados para determinar el tiempo de actividad del servicio. Esto puede permitir identificar otras vulnerabilidades:
Incluso cuando no se han identificado vulnerabilidades durante la enumeración, los servicios RMI disponibles podrían exponer funciones peligrosas. Además, a pesar de que la comunicación RMI con los componentes predeterminados de RMI está protegida por filtros de deserialización, al hablar con servicios RMI personalizados, dichos filtros generalmente no están en su lugar. Por lo tanto, conocer las firmas de métodos válidas en los servicios RMI es valioso.
Desafortunadamente, Java RMI no admite la enumeración de métodos en objetos remotos. Dicho esto, es posible realizar fuerza bruta en las firmas de métodos con herramientas como remote-method-guesser o rmiscout:
Aparte de adivinar, también deberías buscar en motores de búsqueda o GitHub la interfaz o incluso la implementación de un servicio RMI encontrado. El nombre vinculado y el nombre de la clase o interfaz implementada pueden ser útiles aquí.
Interfaces Conocidas
remote-method-guesser marca clases o interfaces como conocidas si están listadas en la base de datos interna de servicios RMI conocidos de la herramienta. En estos casos, puedes usar la acción conocida para obtener más información sobre el correspondiente servicio RMI:
$ rmg enum 172.17.0.2 1090 | head -n 5
[+] RMI registry bound names:
[+]
[+] - jmxrmi
[+] --> javax.management.remote.rmi.RMIServerImpl_Stub (known class: JMX Server)
[+] Endpoint: localhost:41695 TLS: no ObjID: [7e384a4f:17e0546f16f:-7ffe, -553451807350957585]
$ rmg known javax.management.remote.rmi.RMIServerImpl_Stub
[+] Name:
[+] JMX Server
[+]
[+] Class Name:
[+] - javax.management.remote.rmi.RMIServerImpl_Stub
[+] - javax.management.remote.rmi.RMIServer
[+]
[+] Description:
[+] Java Management Extensions (JMX) can be used to monitor and manage a running Java virtual machine.
[+] This remote object is the entrypoint for initiating a JMX connection. Clients call the newClient
[+] method usually passing a HashMap that contains connection options (e.g. credentials). The return
[+] value (RMIConnection object) is another remote object that is when used to perform JMX related
[+] actions. JMX uses the randomly assigned ObjID of the RMIConnection object as a session id.
[+]
[+] Remote Methods:
[+] - String getVersion()
[+] - javax.management.remote.rmi.RMIConnection newClient(Object params)
[+]
[+] References:
[+] - https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html
[+] - https://github.com/openjdk/jdk/tree/master/src/java.management.rmi/share/classes/javax/management/remote/rmi
[+]
[+] Vulnerabilities:
[+]
[+] -----------------------------------
[+] Name:
[+] MLet
[+]
[+] Description:
[+] MLet is the name of an MBean that is usually available on JMX servers. It can be used to load
[+] other MBeans dynamically from user specified codebase locations (URLs). Access to the MLet MBean
[+] is therefore most of the time equivalent to remote code execution.
[+]
[+] References:
[+] - https://github.com/qtc-de/beanshooter
[+]
[+] -----------------------------------
[+] Name:
[+] Deserialization
[+]
[+] Description:
[+] Before CVE-2016-3427 got resolved, JMX accepted arbitrary objects during a call to the newClient
[+] method, resulting in insecure deserialization of untrusted objects. Despite being fixed, the
[+] actual JMX communication using the RMIConnection object is not filtered. Therefore, if you can
[+] establish a working JMX connection, you can also perform deserialization attacks.
[+]
[+] References:
[+] - https://github.com/qtc-de/beanshooter
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}
Utiliza Trickest para construir y automatizar flujos de trabajo fácilmente, impulsados por las herramientas de comunidad más avanzadas del mundo.
Obtén acceso hoy: