コンテナイメージとKubernetesにおけるJDWPの設定ミス #aqua #コンテナ #セキュリティ #kubernetes #k8s #動的解析 #DTA
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
本ブログは「Aqua Security」社の技術ブログで2021年3月18日に公開された「 JDWP Misconfiguration in Container Images and K8s 」の日本語翻訳です。
コンテナイメージとKubernetesにおけるJDWPの設定ミス
Java Debug Wire Protocol(JDWP)は、開発中のアプリケーションをリモートでデバッグするための優れたプロトコルです。しかし本番環境で有効になっていると、ハッカーはこのミスを悪用して、本番環境で初期アクセスや特権昇格を可能にする任意のコードを実行できます。Aqua の調査チームである Team Nautilus は、DTA(Dynamic Threat Analysis)スキャンを使用して Docker Hub で数十個の設定ミスのあるコンテナイメージを検出しました。これらのコンテナイメージは大規模な組織に属しており、本番環境で実行されると深刻なリスクにさらされる可能性があります。このブログでは、攻撃者がこの設定ミスをどのように悪用するかを説明し、コンテナと Kubernetes に対する脅威を説明します。
JDWPとは
開発者はバグを特定して修正するために、コードを入念に検査しています。通常 Java 開発者は統合開発環境(IDE)内のローカルでアプリケーションをデバッグします。しかし、時にはアプリケーションをリモートでデバッグする必要があります。そのためには、Java Debug Wire Protocol(JDWP)を使用します。JDWP は Java 仮想マシン(JVM)ツールインタフェースとデバッグコンソール間の通信プロトコルです。
この機能はデフォルトでは無効になっていますが、有効にすると開発者がリモートでコードをデバッグできます。開発段階でこの機能を有効にし、誤って有効なまま実稼働環境にリリースしてしまった場合、攻撃者はこの設定ミスを利用して、初期アクセスや特権昇格を行えます。リモートの攻撃者は、ネットワーク内または露出したデバッグポート(露出したままの場合)を使用して、JVM に任意の Java クラスをメモリにロードするよう指示し、これを利用してリモートからコードを実行できます。
受信トラフィックを制限せずに VM で JDWP を有効にすると、リモートの攻撃者がこの設定ミスを検出して悪用する可能性があります。この攻撃ベクトルについては、RedTeam Security のブログで詳しく紹介されています。しかし、これはコンテナや Kubernetes からの観点で見た場合、本当に問題となるのでしょうか。
簡単に言ってしまうと、その答えは「問題となる」です。厳密に言うともう少し複雑です。コンテナの場合は、まずデバッガをセットアップして dt_socket をリッスンするポートを設定し、次にコンテナを実行するときにポートを公開する必要があります。コンテナを実行する際にポートを公開する必要があります。
"Don't expose Java debuggers in production! Check out Team Nautilus' interesting research about the risks of leaving open Java debuggers in containers and K8s."
JDWP をコンテナイメージ内で有効にする
JDWP の設定ミスを発見したほとんどのコンテナイメージは、エントリーポイントの JVM 起動コマンドに -agentlib フラグが付いており、Java デバッガをリッスンするポートを定義しています。例えば、以下のスクリーンショットでは、ポート 8000 が JDWP のアドレスとして定義されていることがわかります。
ホスト上のポートを公開せずにこのコンテナイメージを実行した場合、デバッガーは localhost をリッスンするため、この設定ミスを利用できません。そのため、--net=host というフラグを付けるか、-p 0.0.0.0:host_port:container_port というフラグを付けてコマンドを実行する必要があります。これにより、外部のスキャナーで設定ミスが検出され、攻撃者に悪用されてしまいます。以下のスクリーンショットでは、コンテナのイメージタグが「prod」となっており、オーナーが本番環境で使用していることを示している可能性があります。
さて、本番環境でコンテナを稼働させ、外部からの攻撃者の行動をシミュレートしてみます。まず、スキャンツールを実行してみましょう。下図のように、nmap スキャンでは、ポート 8000 が開いており、Java Debug Wire Protocol をリッスンしていることがわかりました。
攻撃者は、この設定ミスを悪用するために、いくつかの既製の Offensive Security Tools(OST)を使用できます。
そのうちの1つは、Metasploit フレームワークのモジュールを持っています。私たちは、一般的な Metasploit パッケージを備えた Kali Linux を使用し、java_jdwp_debugger をロードしました。そして、攻撃対象のホストの IP とポート、攻撃者の IP とペイロードなどの関連する変数を定義しました。Metasploit をデフォルトのパッケージで実行したところ、セッションの作成に失敗しました。そこで、リバースプロキシのペイロードを使用して、エクスプロイトを実現することができました。
上と下のスクリーンショットに見られるように、この方法は実際に機能し、コンテナに対して root 権限で shell login できました。
さて、最初のアクセスを得た後は、機密情報の検出・収集や特権昇格を目的とした攻撃を続けることができます。例えば、悪用後の OST スクリプトを実行して認証情報を収集したり(punk.py)、BOB を使ってホストに移動しようとします。これらの技術に関する詳細は、脆弱な Kubernetes クラスターを検出して悪用するために設計された、初のコンテナイメージに関するブログをご覧ください。
JDWP を Kubernetes クラスター内で有効にする
コンテナイメージと同様に、Kubernetes で実行する場合、Pod は0.0.0.0:8090 の下で実行する必要があります。そうしないと、localhost(127.0.0.1)にリストアップされ、外部の攻撃者はアクセスできません。Kubernetes では、このポートはネットワークに対して開かれており、クラスター内の別の Pod がこの設定ミスを悪用できます。今回のケースでは、この設定ミスを悪用するために、JDWP-shellifier.py を使用しました。
この設定ミスがコンテナと Kubernetes の両方で悪用できることを確認したところで、残る問題はこの設定ミスが外部環境から見つけられるかどうかです。
答えは「見つけられる」です。Aqua の Team Nautilus は、DTA(Dynamic Threat Analysis)スキャンを使用してDocker Hubのオープンレジストリーをスキャンし、これらの設定ミスがある数十個のコンテナイメージを発見しました。これらのイメージの中には、テスト環境に関連するものもあるようですが、本番環境やK8sクラスターで使用されているものもあるようです。Team Nautilus は、1年間で 114 の異なる Docker Hub アカウントから、JDWP の設定ミスがあるコンテナイメージを少なくとも1つ検出しました。合計で 193 の異なるコンテナイメージを確認しています。
上のグラフでは、月ごとに新しい JDWP の設定ミスが検出されていることがわかります。明らかに、JDWP を設定ミスされたコンテナイメージが多数あり、それらが本番環境で使用された場合、遠隔地の攻撃者に機密エリアへの初期アクセスを許してしまう可能性があります。
緩和策とまとめ
このような設定ミスは、一見すると難解なものに見えますが、攻撃者が本番環境へ簡単にアクセスするよう利用できます。そのためデータを盗んだり、本番環境に損害を与えたり、より悪質な攻撃をするための初期アクセスを得ることができます。
では、どうすればいいのでしょうか。
- 本番環境では、JDWP を使用しないでください。エージェントを有効にしないで JVM を起動してください。運用イメージでは、-agentlib、-Xrunjdwp、-Xdebugの各引数を使用しないでください。
- ネットワークやセキュリティポリシーの設定を変更して、信頼できるホストにのみ適切な権限を与えることで、リモートデバッグを信頼できるホストに制限してください。
- Aqua 社の DTA のような動的脅威解析ツールを使って、コンテナイメージの JDWP 設定ミスをスキャンします。例えば上の図は DTA によって検出された JDWP の設定ミスを示しています。