Apache Log4j のリモートコード実行可能な脆弱性 "Log4Shell" CVE-2021-44228 を簡単に整理します
2021年12月10日に Apache Log4j (以下単に Log4j と書きます)の致命的な脆弱性の情報が共有されました。Log4j は Java で書かれたソフトウェアにおけるポピュラーなロギングライブラリです。そのため、この脆弱性の世界的な影響度合いは非常に大きく、現在注目を受けています。例えばゲームの「マインクラフト」でもこのライブラリが使われており、多くのゲームサーバがメンテナンスのため一時的に停止しました。
この記事ではこの脆弱性、通称 Log4Shell について情報を簡単に整理します。備忘録のようなものですので、不正確だったり分かりづらいところがあるかもしれません。不正確な部分については確認でき次第訂正します。
この記事を書くにあたり、いくつかの再現テストを行っています。再現方法については載せませんが、それを踏まえた調査結果も一部載せています。
なお、既に Piyokango 氏が『Log4jの深刻な脆弱性CVE-2021-44228についてまとめてみた』という記事でまとめてくださっています。手っ取り早く状況を確認したい方はそちらをご覧ください。
また他の方の記事『【図解】Log4jの脆弱性 CVE-2021-44228 (Log4shell or LogJam) について』にて原理、対策方法を分かりやすくまとめてくださっています。
追記(2021.12.14)
Log4j の 2.16.0 が公開されました。メッセージから Lookups の呼び出しが行われなくなりました。また JNDI Lookup の機能がデフォルトで無効化されています。
入力データをログに出力する際、その入力データを元に Lookups のような式評価や副作用が発生するのはリスクが大きく、今回と同様の脆弱性が発見される可能性があるので、2.16.0 にアップデートすることをおすすめします。
経緯
問題となったのは Lookups という機能でした。この機能はログに動的な値を埋め込む便利な機能です。
この Lookups の中には Jndi Lookup という機能が含まれています。JNDI とは Java Naming and Directory Interface のことで、簡単に言えば名前とオブジェクトを紐づけるためのものです。この機能を使えば指定した名前に紐づくオブジェクト、つまりクラスファイルをロードして実行し、その結果をログに出力することができます。
ここで肝心なのはオブジェクトへの参照にはリモートも含まれるということです。つまり JNDI を悪用された場合、リモートに配置した悪意のあるコード(クラスファイル)をサーバに読み込ませるという攻撃が成立します。
そのため、以前から JNDI Lookup の参照設定に信頼できないデータを含めるべきではないという注意喚起がなされていました。この攻撃方法は JNDI Injection と呼ばれています。
また、Log4j には特定の文字列を出力することで、この JNDI Lookup を呼び出す機能が含まれています。私が確認したところ、メッセージでも、パラメータでも、特定の書き方をすれば JNDI Lookup を呼び出すことができました。メッセージの書き方一つで JDNI Lookup を呼び出せると気付く人はなかなかいないのではないでしょうか。
これでメッセージに不正な文字列を埋め込めば、JNDI Injection により不正なコードを実行できるというラインが繋がりました。メッセージに不正な文字列を埋め込むというのはそれほど難しくはありません。というのも、どんなサーバアプリケーションにしろユーザ入力をログに出力するというのはごく一般的な処理だからです。ユーザ入力を Log4j でログ出力するということは、メッセージに不正な文字列を混ぜ込むのも容易だということです。
2021年11月30日に Log4 の JNDI Lookup に関するプルリクエストが登録されました。簡単に言えば Log4 から JNDI によるオブジェクト参照について、ホワイトリスト設定を追加しようというものです。その数日後、このプルリクエストに対し、これは脆弱性ではないか?という Twitter のツイートやプルリクエストのコメントが投稿されました。この脆弱性が致命的であるということから、マインクラフトのような有名なソフトウェアでも使われているということもあり、一気に話題になったというのが現状です。
現在は Log4j 2.15.0 というバージョンで上記のプルリクエストが取り込まれています。
今回の事例は肥大化した Log4j の不安定な部分が粗として見つかった形だと思います。プルリクエスト中にコメントされていますが、まさに以下のリンクに掲載されているようなイメージです。
今回は以下の問題が積み重なった結果、致命的な脆弱性となってしまいました。
Log4j は JNDI Lookup の機能があり、この機能を悪用されると任意のコードが実行できる状態だった。
JNDI Lookup の機能はデフォルトで有効だった。
JNDI Lookup からどんなリモートサーバにもアクセス可能だった。(特にフィルタリングされていなかった。)
Log4j にはメッセージに特別な書き方をすることで JNDI Lookup を呼び出す機能があった。
メッセージから JNDI Lookup を呼び出す機能はデフォルトで有効だった。
なお JNDI Lookup の機能は Log4j 1.x の時代から存在しています。JMSAppender というクラスに JNDI Lookup を行う処理が記述されています。しかし、JMSAppender はサーバ設定ファイルに明示的に書かなければ機能しないという点、仮に JMSAppender が有効であっても JNDI の接続先をサーバ管理者が意図的に変えない限り、悪意のあるコードは読み込めない点から Log4j 1.x では機能しない、というのが 12月13日 現在の認識です。(だからと言って Log4j 1.x で良かった、これからも古いバージョンでいけばいい、という訳ではないのですが。)
影響
条件が極めて緩いリモートコード実行脆弱性ということもあり、攻撃の用意さ、影響度合いから見て甚大な影響があります。広範囲にわたる機密情報の漏洩、改ざん、サービスの停止、バックドアの設置など、様々な影響が生じる可能性があります。
Log4j は思わぬところで利用している可能性があります。例えば全文検索エンジンの Apache Solr にも使われておりニュースにも対処方法が既に掲載されています。シンプルな探し方はサーバ上を log4j という文字列で検索してライブラリファイル(拡張子 jar)を見つけることです。またもっと確実な方法として -verbose:class オプションを使った方法が『-verbose:class オプションを使ってLog4j利用の有無、Log4jを利用しているクラスを調査する』という記事にて紹介されています。
対処方法
基本的な対処方法としては JPCERT や Piyolog にて対策方法が紹介されていますので、そちらを参照してください。
com.sun.jndi.*.object.trustURLCodebase について
Java の実行環境を新しくすると com.sun.jndi.ldap.object.trustURLCodebase や com.sun.jndi.ldap.object.trustURLCodebase というパラメータがデフォルトで有効になり、信頼できないリモート URL からコードを読み込むのをブロックできます。
ただしこれらのパラメータが有効な場合であっても、Log4j を組み込んでいるフレームワークや、アプリケーションコードの既存機能を用いて任意のコードを実行できること確認しています。例えば Apache Tomcat を使用している場合は、新しいバージョンの Java 実行環境であっても、内包される機能を利用して任意のコード(今回は Windows 電卓の起動)を実行できることを確認しました。
そのため、実行環境を新しくすると対処は一時的な対処だとして認識して、バージョンを 2.5.0 にするか、-Dlog4j2.formatMsgNoLookups=true を設定するか、いずれかの対処を早急に行うことをおすすめします。
アウトバウンド通信の制限
これを機にアウトバウンド通信の制限をしていなかった重要性の高い システムはコストをかけて制限の導入を進めても良いかと思います。今回のケースでは JNDI Lookup におけるアウトバウンド通信を抑制することで攻撃を防ぐことができました。
攻撃ログの情報収集が進めば、JNDI Lookup のブロック用リストが作られ、ブラックリスト方式で遮断することも可能になりますが、2021年12月13日 12:00 時点ではまたそのようなリストを確認できていません。(仮にリストが作られたとしてもブラックリスト型の対処はいたちごっこになってはしまいますが。)
ログによる検知
Web サーバのログを特定のパターンで検索すると攻撃の兆候を検知できます。jndi という文字列で検索して見つかった場合は攻撃を受けている可能性があります。ただし攻撃が成功しているか否かの判別は難しいです。
攻撃側も様々な文字列パターンを用意しているようですが、jndi という文字列で概ね兆候はつかめると思います。
ただし、POST パラメータや HTTP ヘッダに攻撃用の文字列が含まれている可能性もあります。ですので、検索結果に jndi が無いからと言って安心はしないようにしてください。
まとめ
Log4j という非常に広く使われているライブラリにて脆弱性が見つかったため、世界的に見ても重要な事案となってしまいました。
しかしマインクラフトサーバ界隈における対応の速さは素晴らしかったと思います。早急にサーバを停止し、バージョンアップあるいは設定変更を行うという対処が見られました。とてもスピード感のある対応だったと思います。
しばらくはこの脆弱性についてウォッチしたいと思います。類似する脆弱性が見つかる可能性もあるので、その点については特に見ていきたいです。