脆弱性の概要
Log4Jとは、Apacheが開発するJava用のロギングライブラリ。
Log4Jには、lookupという機能が含まれており、ログ出力時にランタイムに情報を出力することができる。
例として、${java:runtime}
という文字列は、Javaのバージョン文字列に置換される。
その中でも、今回原因になったのは、Jndi Lookupである。
Jndi Lookupは、ネットワーク上から値を取得し置換するものである。
使用すると、LDAPのようなディレクトリへアクセスするプロトコルを経由して外部ファイルへのアクセスを実行させることが可能である。
そのため、ネットワーク上にJavaクラスファイルを配置したLDAPサーバーを構築し、URLをLookupの文字列に当てはめ送信するとJava Runtimeでそのプログラムが実行される。
手法
LDAPサーバーを構築し、実行したいクラスファイルを配置する。
その後、URLを以下のように当てはめ、それをLog4Jで出力させる。
(QiitaはJava製なのか貼れないようになっていたため、pastebin)
https://pastebin.com/mEtekHPf
対象となるシステム
バージョン2.0から2.14.1までのLog4Jに影響します。
以下の条件が揃っていると、任意のプログラムを実行することができます。
・攻撃者が任意のデータを送信できるプロトコルを備えたリモートアクセス可能なエンドポイント
・攻撃者がエンドポイントに送信した任意のデータをLog4Jを介して記録すること
Minecraftサーバー
Minecraftはクライアントとサーバー側、両方にLog4Jを用いている。
そのため、MinecraftのチャットにLookupの文字列を送信すると、サーバー側と他のクライアント上で悪意のあるプログラムが実行されると考えられる。
Webサーバー
例として、フォームで入力された文字列をLog4Jを用いて出力するようにされている場合、フォームにLookupの文字列を送信すると、サーバー側で悪意のあるプログラムが実行されると考えられる。
対策
アップデートされたLog4Jを使用する
Log4j 2.15.0にはすでに対策が施されているため、アップデートすることで脆弱性の悪用が防げる。
JVM引数によるLookupの無効化
JVM引数として、-Dlog4j2.formatMsgNoLookups=true
を設定するとLookupが無効になりプログラムの実行が行われない。
なお、Minecraftサーバーのようにクライアント側でもLog4Jが使われている場合は、サーバー側のみで対策してもクライアント側は実行される。
Log4Jの設定ファイルによるLookupの無効化
出力パターンを以下のように設定すると、Lookupが無効化される。
jar内の設定ファイルを置き換えるか、実行時に-Dlog4j.configurationFile=log4j2.xml
のようなフラグで指定できる。
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n"/>
出典・参考
最後に
間違いがあった場合は、コメント等で指摘いただけると幸いです。