Log4Shell - Log4jの脆弱性(CVE-2021-44228)を検出する(続報)

Security Marcus LaFerrera

者/寄稿者:Splunkのセキュリティはいつでもファミリービジネスです。この記事は、Ryan Kovar、Shannon Davis、Johan Bjerke、James Brodsky、Dave Herrald、John Stoner、Drew Church、Mick Baccio、Jay Holladay、Lily Lee、Audra Streetman、Tamara Chaconの協力のもと執筆されました。

最新情報:Log4j RCE

Splunk SURGeチームは先日、世界中のセキュリティ防御チームに徹夜の対応を迫ったLog4jの脆弱性「Log4Shell」について、Splunk製品での対策をまとめた速報ブログセキュリティアドバイザリーを公開しています。

このブログでは、組織への攻撃の検出方法に関する追加の最新情報をお伝えします。攻撃の兆候を検出するために必要なログを収集していなくても、まだ間に合います。自社のホストが標的になっているかどうかを調査する方法がほかにも見つかりました。

Log4Shellの動作を検出する

スイスCERTは、この攻撃の各段階の概略を示す図を含む有用なブログを公開しました。この図には、検索の鍵となる情報も示されています。

Splunkでの検出方法は第1~2段階に集中しています。この段階では、脆弱性のあるサーバーに、攻撃の足掛かりとなるJNDIリクエストが送られます。

このログを記録していない場合でも、第3段階で検出する良い方法があります。そこで重要になるデータソースが、ネットワークトラフィックログとDNSクエリーログです。以下では、この2つのログを使用して、組織の環境内で侵害されたホストを検出する方法をご説明します。

SplunkでLog4Shell (Log4j 2 RCE)攻撃を検出する

侵入検知アラート

前提としてIDSの導入は欠かせません。IDSのルールを最新の状態に更新し、Splunkでアラートをインデックスするように設定していることを確認してください。ここではSuricataを使用しますが、この脆弱性のシグネチャに対応したIDSであれば製品は問いません。攻撃を検出するにはまず、次のインデックスをサーチします。

index=suricata ("2021-44228" OR "Log4j" OR "Log4Shell") 
| table _time, dest_ip, alert.signature, alert.signature_id

組織のネットワークから外部へのLDAPアクセスを検出する

組織と外部のネットワーク境界にあるファイアウォールで外部へのLDAPトラフィックを許可することはまずないでしょう。このトラフィックが検出された場合は、Log4Shellの初期アクセス活動が行われている可能性があります。SplunkのベストプラクティスとNetwork Trafficデータモデルを使用したtstatsによるサーチがこちらです。このサーチを使えば、プライベート(RFC1918)アドレス範囲外のIPアドレスに対するLDAP接続を検出できます。

| tstats earliest(_time) as earliest_time latest(_time) as latest_time values(All_Traffic.dest_ip) from datamodel=Network_Traffic.All_Traffic where All_Traffic.dest_port = 1389 OR All_Traffic.dest_port = 389 OR All_Traffic.dest_port = 636 AND NOT (All_Traffic.dest_ip = 10.0.0.0/8 OR All_Traffic.dest_ip=192.168.0.0/16 OR All_Traffic.dest_ip = 172.16.0.0/12) by All_Traffic.src_ip
| convert ctime(earliest_time) ctime(latest_time)

JNDIプローブとDNSクエリーを相関付ける

Log4jの脆弱性悪用の兆候を示すJNDI文字列の検出方法はすでに特定しています。では、その結果とプローブ(攻撃前の探査)の成功をどのように相関付ければよいでしょうか。ここで役立つのがDNSです。

最初のサーチでは、まず、正規表現を使ってJNDI文字列からドメインを抽出します。次に、抽出したドメインを追加してルックアップテーブルを更新します。このルックアップテーブルは次のサーチで使用します。このクエリーでは非構造化データを処理するため、通常のCPUサイクルの数倍、サーチするデータ量によってはある程度の時間がかかることに注意してください。このサーチを初めて実行するときは、まずルックアップファイルを作成するために、クエリー内のlookup行をコメントアウトしてください。

index=*  jndi
| rex field=_raw max_match=0 "[jJnNdDiI]{4}(\:|\%3A|\/|\%2F)(?\w+)(\:\/\/|\%3A\%2F\%2F)(\$\{.*?\}(\.)?)?(?[a-zA-Z0-9\.\-\_\$\{\:]+)"
| mvexpand rce_dest
| rex field=rce_dest "(?\d+\.\d+\.\d+\.\d+)"
| eval rce_domain = case(isnull(rce_ip),rce_dest)
| rex field=rce_domain "(?[0-9a-zA-A\-]+\.[0-9a-zA-A\-]+$)"
| dedup top_level_domain
| eval top_level_domain = "*.".top_level_domain
| where top_level_domain!=""
| lookup log4j_scanning_domain.csv query as top_level_domain OUTPUT query AS old_query
| where isnull(old_query)
| rename top_level_domain as query
| table query
| outputlookup append=t log4j_scanning_domain.csv

上記のサーチが完了すると、ドメインを格納したルックアップテーブルが作成されるので、Network Resolutionデータモデルを使ってtstatsサーチを実行し、JNDIプローブのドメインと一致するDNSクエリーを探します。

| tstats summariesonly=true allow_old_summaries=true
      values(host) as host, values(DNS.query_type) as DNS.query_type, values(DNS.reply_code) as DNS.reply_code, values(DNS.transport) as DNS.transport
      count from datamodel=Network_Resolution.DNS
      where [| inputlookup log4j_scanning_domain.csv | rename query as DNS.query | format] 
      by "DNS.src",sourcetype, DNS.query index _time span=1s
| stats earliest(_time) as first_seen, latest(_time) as last_seen sum(count) as count, values(DNS.reply_code) as DNS.reply_code, values(index) as index, values(DNS.src) as DNS.src, values(DNS.query_type) as DNS.query_type, values(DNS.transport) as DNS.transport by host DNS.query sourcetype
| convert timeformat="%m/%d/%Y %H:%M:%S" ctime(first_seen), ctime(last_seen)

新しいアウトバウンドトラフィックを検出する

2021年12月9日以前に送信トラフィックを生成していない内部サーバー(Egress)からのアウトバウンドトラフィックを検索する方法もあります。そのためには、期間をこの日(2021-12-09)の24時間以上前に設定して、標準的なトラフィックと比較できるようにします。このように挙動サーチの範囲を拡大すると、検索時間は長くなりますが、検索網を最大限に広げて侵害の兆候を捉えることができるメリットがあります。基本となるSPLがこちらです。

index=* src_ip=* dest_ip=* 
(NOT (dest_category="internal" OR dest_ip=10.0.0.0/8 OR dest_ip=172.16.0.0/12 OR dest_ip=192.168.0.0/16 OR dest_ip=100.64.0.0/10))
| stats
earliest(_time) as earliest 
latest(_time) as latest 
values(action) as action 
values(app) as app 
values(dest_port) as dest_port 
values(sourcetype) as sourcetype count 
by src_ip dest_ip
| eventstats max(latest) as maxlatest
```This is 2021-12-09 00:00:00```
| eval comparisonTime="1639008000"
```| eval comparisonTime="-1d@d" ```
| eval isOutlier=if(earliest >= relative_time(maxlatest, comparisonTime), 1, 0)
| convert timeformat="%Y-%m-%dT%H:%M:%S" ctime(earliest),ctime(latest) ,ctime(maxlatest)
| where isOutlier=1

このサーチはいくつかの方法で変更できます。

このブログはこちらの英語ブログの翻訳、藤盛 秀憲によるレビューです。

関連記事

Splunk×LanScope Catによるテレワークでの労務状況の可視化
セキュリティ
3 分程度

Splunk×LanScope Catによるテレワークでの労務状況の可視化

新型コロナウィルスの影響で、急遽テレワークを実施した企業様も多いのではないでしょうか。MOTEXでも順次テレワークを開始し、現在では98%とほぼすべての社員が自宅で業務を実施しています。今回はテレワークの課題解決に向けて労務状況可視化に特化したレポート作成に取り組みました。
ランサムウェアは45分未満で約10万ファイルを暗号化する
セキュリティ
3 分程度

ランサムウェアは45分未満で約10万ファイルを暗号化する

Splunk SURGeの調査により、組織はランサムウェアへの対応や軽減よりも感染防止に注力する必要があることが明らかになりました。
M365インベーダーハンティング:ブルーチームのための初期アクセスベクトル対策ガイド
セキュリティ
26 分程度

M365インベーダーハンティング:ブルーチームのための初期アクセスベクトル対策ガイド

Microsoft 365の脅威検出について、データソースの分析と、初期アクセスを試みる脅威の効果的なハンティング方法を中心に、Splunk脅威調査チームの知見をご紹介します。