公開されたPrometheusサーバーを利用したKubernetesクラスターへの攻撃方法について

By 清水 孝郎 - JULY 6, 2022

SHARE:

本文の内容は、2022年7月5日にMiguel Hernándezが投稿したブログ(https://sysdig.com/blog/exposed-prometheus-exploit-kubernetes-kubeconeu/)を元に日本語に翻訳・再構成した内容となっております。

セキュリティの観点からは、自分のメトリクスは無害だと思うかもしれません。KubeCon Valencia 2022でのこの講演では、Prometheusサーバーが公開されるリスクと、攻撃者がこの情報を使ってKubernetesクラスターへのアクセスに成功する方法を共有しました。

 

スライドはこちらでご覧いただけます。また、ソーシャルメディアやブログでの言及を集めたところ、非常に好評でした:

 

KubeConにスピーカーとして参加するのは初めてで、期待値はとても高かったです。採択率12%(私たちを受け入れてくれたCNCFとレビュアーに感謝)、1,300人以上の参加者が私たちの講演に登録してくれたので、緊張しなかったと言えば嘘になります。では、さっそく始めましょう。

Kubernetes fingerprinting with exposed Prometheus
一番説明したいことは何でしょうか?それは単純で、メトリクスをフリーで公開してはいけないということです。

時々、私たちは深くて複雑な防御方法について考えることがありますが、それはそれで構いません。なぜかわかりませんが、私たちはいつも基本的なことを忘れています。データを公開してはいけません。デフォルトでは、Prometheusサーバーは、誰でもKubernetesクラスターから情報を取得するためのクエリーを作成できるようになっています。

これは新しいことではありません。2018年、Teslaはクラウドアカウントに暗号通貨マイニングのアプリケーションを入れていましたが、最初のアクセスは、クレデンシャルが明らかになったKubernetes Dashboardが公開されたものでした。

さらに、監視ツールの(中略)セキュリティについて語るのは、私たちが初めてではありません。ここでは、3つの良い例を紹介します:

では、Prometheusのサーバーは本当に攻撃対象なのでしょうか?

野ざらしにされたPrometheus

ペンテストや倫理的ハッキング、あるいは実際の攻撃において最も重要なステップの1つは、ターゲットから得られる情報をできるだけ多く収集することです。

インターネット上で何かが公開されているかどうかを確認する最も手っ取り早い方法は、Googleにクエリーを出すことです。情報収集のための具体的なクエリーは、Googleドーキングと呼ばれ、私たちの場合は、実際に公開されているPrometheusを取得するための些細なものです。

公開されているPrometheusサーバーを見つけるには、検索エンジンを利用する方法があります。ここでは、最も一般的な検索エンジンを使って、アクセス可能なサーバーの数を調べてみました。

検索エンジンPrometheusが公開されているサーバ数
Shodan31,679
Censys61,854
Fofa161,274

ここで、重要な事実を明らかにしておきたいと思います。

免責事項:私たちは、この講演の相談や準備のために、実際に公開されたPrometheusサーバーを使用したわけではありません。私たちは、すべてのテストを私たちのデモ環境で行いましたが、常にセキュリティのベストプラクティスに従うことを強くお勧めします。 その後、Prometheusサーバーにアクセスし、フィンガープリントKubernetesにアクセスできるようになった場合、何ができるのでしょうか?

PrometheusのエクスポーターとフィンガープリントKubernetes

Prometheusは、Kubernetesにおけるデファクトスタンダードのモニタリングです。コントロールプレーンのすべてのKubernetesコンポーネントは、箱から出してPrometheusメトリクスを生成し、多くのKubernetesディストリビューションは、一般的に一連の標準エクスポーターを含むPrometheusがデフォルトでインストールされています。

  • インフラストラクチャーとホストメトリクスのためのノードエクスポーター
  • Kubernetesオブジェクトの状態メトリクスのためのKSM エクスポーター
エクスポーターとは、Prometheusのメトリクスをネイティブに公開していない他のアプリケーションやシステムにおいて、メトリクスを生成するためのアプリケーションです。

クラウドプロバイダー、どこにいる?

www.example.com にターゲットになりそうなものがあると想像してください。

あなたが知っているのは、このサイトがユーザーとちょっとしたeコマースセクションを持つWebページであるということだけです。そのドメインの下に、公開されているPrometheusを見つけます。最初にできることは、このサイトがホストされているクラウドプロバイダーを特定することです。

ノードエクスポーターから node_dmi_info というメトリクスが使用できます。このメトリクスは、各ノードに関する情報を提供するため、非常に興味深いものです。

  • システムベンダー:クラウドベンダーの名前が表示されます。値の例としては、”Amazon EC2 “や “Tencent Cloud “があります。
  • 製品名:クラウドプロバイダーと使用されている製品の両方を特定するのに便利で、AWS EC2のカタログから人気のある製品名(m5.xlargeなど)や他のベンダーの製品を見つけることができます。
しかし、クラウドプロバイダーは、たとえ興味深いものであっても、まだとても曖昧です。ネットワークに着目すれば、もっと情報を集められるはずです。ノードエクスポーターの node_network_info というメトリクスから始めるとよいでしょう。そしてさらに、Ethernetインターフェースだけをフィルタリングすれば、検索を絞り込むことができます。

なぜイーサネットだけなのか?なぜなら、通常、それらはホストが物理的なネットワーク接続として識別し、ホストを外の世界や他のマシンと接続するために使用されるものだからです。

node_network_info{device=~'eth.+'}

このクエリーは以下の情報を提供します:

  • 各ホストのIPアドレス
  • デバイスID
  • クラウド事業者のアベイラビリティゾーン
  • VPC (Virtual Private Cloud) の ID
以下は、いくつかの取得できる可能性がある値の例です:

    address="06:d5:XX:XX:XX:XX"
    broadcast="ff:ff:ff:ff:ff:ff"
    device="eth0"
    instance="172.31.XX.XX:9100"
    instance_az="us-west-2a"
    instance_id="i-XXXXX"
    instance_name="XXX-XXX"
    instance_type="c5.xlarge"
    instance_vpc="vpc-XXXXXXX"
    operstate="up"

また、KSMのkube_node_info というメトリクスで各ノードのホスト名など、より詳細な情報を取得することができます。

Podまでの長い長い道のり

ここまでが物理的な情報でしたが、Webページの外からクラスター内のPodにたどり着くにはどうしたらよいのでしょうか?その答えは、ingressservicesにあります。

Kubernetesのingressコントローラーはリバースプロキシとして機能し、URLの異なるパスを異なるKubernetesサービスにリダイレクトすることを可能にします。これらのサービスは通常、接続用のポートを公開する一連のPodの前でロードバランサーとして動作します。KSMのメトリクス kube_ingress_path は、クラスター内のingressコントローラーのURLパスと関連するサービスについての情報を提供します。

この方法では、パス  /api/users/login がネームスペース  api の Kubernetes サービス  users-login に行くことを知ることができます。面白いでしょう?

ロードバランサーサービスは、Kubernetesのサービスの中でも特殊なものです。クラウドプロバイダーは、それらのロードバランサーサービスを利用して、サービスを外部に公開します。例として、AWS Kubernetesクラスターでロードバランサーサービスを作成すると、そのサービスにバインドされたELB (Elastic Load Balancer) インスタンスが作成されます。

このpromQLクエリーでは、Kubernetesクラスター内のすべてのロードバランサーサービスに関する情報を得ることができます。

kube_service_info * on (service) group_left group by (service,type) (kube_service_spec_type{type="LoadBalancer"})

各サービスの背後にあるPodを推測するには、2つのオプションがあります。KSMのkube_pod_labels というメトリクスを確認することができます。これらのラベルは、通常サービスがリクエストに対応するPodを選択するために使用するものですが、残念ながら純粋なKSMではPodとサービスの関連性を取得する直接的な方法は存在しません。

しかし、運が良ければ、インフラエンジニアがクラウド利用のコストを理解するためのツールであるOpenCost exporterがクラスターにインストールされているはずです。このエクスポータは  service_selector_labels という興味深いメトリクスを生成します。これは、サービスと、その特定のサービスの一部になるために Pod が持つ必要のあるラベルとの関連性を直接的に示してくれます。

このpromQLクエリーは、サービス内のマッチングに使用される各ワークロードのラベルを提供します:

avg by (namespace,label_app,owner_name)(kube_pod_labels{app="cost-model"} * on(namespace,pod) group_left(owner_name) kube_pod_owner{job="kube-state-metrics"})

一方、もう一つは各サービスがPodを見つけるために使用するラベルを得ることができます:

avg by (namespace,label_app, service)(service_selector_labels)

多対多の関連なので,1つの promQL クエリーでこれらすべての情報を収集するのは簡単ではありませんが,情報はありますし,サービスと Pod の相関を簡単にとることができます.

このようにして,URL から Pod へのパスのすべてのポイントが得られます:URL のパス(イングレスのおかげ),リクエストを提供する Pod(Podのサービスやラベルのおかげ)です.

Exposed Prometheus to gather Kubernetes network information

クラスターのロジカルな楽曲

ノードに関する情報を取得するためにメトリクス kube_node_info を使用しましたが、今度はKubernetesクラスター内のネームスペース、ワークロード、Podの論理マップを作成することにも興味があるはずです。

これは、KSMメトリクスを使用することで簡単に行えます。kube_namespace_status_phaseというメトリクスを使うと、クラスター内のすべてのネームスペースが分かります。そこから、異なるワークロードの種類ごとに、以下のメトリクスで突き詰めていくことができます:
  • kube_deployment_spec_replicas
  • kube_daemonset_status_desired_number_scheduled
  • kube_statefulset_replicas
  • kube_replicaset_spec_replicas
  • kube_cronjob_info

後は、以下のpromQLで、 kube_pod_infoでPodの情報を取得し、 kube_pod_owner でワークロードと関連付けます。

kube_pod_info * on(namespace,pod) group_left(owner_name) kube_pod_owner

最後に、 kube_pod_container_infoというメトリクスで、各Pod内のコンテナを取得することも可能です。例えば、 postgres-db というPodは、 postgresql  postgres-exporterという2つのコンテナを持つことができます。

しかし、それだけではありません。Podのネームスペースとワークロードを知ることができるだけでなく、メトリクス kube_pod_infoのラベル node のおかげで、そのPodが存在するノードを発見することができます。なぜこれが重要なのでしょうか?続けてお読みください。

壊れたノードの大通り

以前、各ノードのホスト名を取得するためにkube_node_infoというメトリクスを使用しましたが、このメトリクスにはさらなる驚きがあります。

このメトリクスの2つのラベルは、ノードをビルドするために使用されたOperative Systemイメージと詳細なカーネルバージョンに関する完全な情報を与えてくれるでしょう。
  • os_image
  • kernel_version

CVEで” Ubuntu 18.04.4 LTS” または “Linux 3.10.0-1160.59.1.el7.x86_64” を素早く検索すると、攻撃者はマシンにアクセスできた場合に使用するエクスプロイトの良いセットを入手することができます。

K8sについて話しましょう

ここまでで、クラスターに関する情報をよく集めることができました。ネームスペース、Pod、サービスなど しかし、Kubernetesそのものについてはどうでしょうか?Kubernetes自体には、ただそこにあるだけで、問題を起こさない限りは考えもしないような処理のセットが存在します。Kubernetesのコントロールプレーンについて話しているのです。

コントロールプレーンの各コンポーネントの具体的なバージョンを指定するメトリクスがあると言ったら、あなたはどう思いますか?Prometheusの発表の際、Kubernetesのコントロールプレーンのコンポーネントはネイティブでメトリクスを公開していると言いました。さて、そのメトリクスの1つがkubernetes_build_infoです。これは、各コンポーネントの完全な(メジャーとマイナーの)バージョンだけでなく、gitコミットやビルド日についての情報を提供します。

これは、具体的な脆弱性がクラスターのコントロールプレーンコンポーネントの1つに影響を与えるかどうかを知りたい場合に最適です(他のことも含めて)。

私たちにはシークレットがある…

誰もがシークレットが好きです。特に攻撃者はそうです。KSMでは、 kube_secret_infoというメトリクスがあり、クラスタのシークレットのネームスペース、ノード、名前に関する情報を得ることができます。

シークレットの内容を知りたい場合は、このクエリーを使用することができます:

kube_secret_annotations{kubectl_kubernetes_io_last_applied_configuration != ""}

なぜか?まあ、これは何となく恥ずかしいですね。 kubectlの古いバージョンでは、最後に適用した設定をアノテーションに保存していたものがありました。これはシークレットを含むすべてのオブジェクトに対して行われていました。これは、たとえシークレットが想像できるようなサービスアカウントやロールバインディングでしかアクセスできないとしても、Prometheusはそのメトリクスでシークレットの内容を平文で公開することができるという効果があったのです。

イメージとレジストリについて

もう十分だと思いますか?もう一つ、KSMから得られる面白いものがあります。 kube_pod_container_info というメトリクスには、これらのラベルの中に興味深い情報があります。

  • imageコンテナのイメージの名前とタグ(例:docker.io/library/cassandra:3.11.6)
  • image_id:コンテナのイメージの名前、タグ、ハッシュ
これによって、以下の情報が得られます。

  • 使用しているアプリケーション
  • イメージを取得するために使用したレジストリ
  • 使用されたイメージ
  • イメージのタグ
  • タグとは別にイメージを一意に識別するためのハッシュ

まとめ Kubernetesのフィンガープリント

ここまでで何をしたのか見てみましょう。以下の情報を集めましたね。

  • クラウドプロバイダー
  • Kubernetesのコントロールプレーンコンポーネントのバージョン
  • 外部からPodへのネットワークパス
  • ノードのホスト名とIP
  • オペレーティングシステムとカーネルバージョン
  • クラスターのネームスペース、ワークロード、Podの論理構造
  • ソースリポジトリからイメージタグまでの、コンテナに使用されるイメージ
  • クラスターのシークレットのアノテーションと名前

Exposed Prometheus fingerprinting Kubernetes CVEs
これらの情報は、クラスターにおける有効なアタックサーフェイス分析を行うために十分なものです。

忍者モード!

何か面白いことを聞きたいですか?私たちはこれらの情報をすべて集めましたが、ほとんどの場合、それを得るために行ったすべてのクエリーの痕跡はありません。Prometheusはクエリーのログを登録することができますが、デフォルトでは無効になっています。このメトリクスを使えば、自分の行動がログに残っているかどうかを確認することもできます。

prometheus_engine_query_log_enabled

攻撃者の頭の中

さて、攻撃者はターゲットが何であるかを知るだけでよいのです。99%の攻撃ではお金ですが、どうやって被害者からお金を奪うか、そこが攻撃者の道筋を決めるポイントになります。

Three Kubernetes threats: leaks, crypto mining and ransomwareKubernetesの3つの脅威:リーク、クリプトマイニング、ランサムウェア

講演では、3つの事例を公開しましたが、それぞれ悪用されるツールやサービスは異なります。重要なのは、どこに弱点があるのかが既に分かっていることです。

機密データの漏洩

最初のシナリオでは、公開されたアプリケーションはKubernetesクラスター上で動作しており、攻撃者は無許可でデータにアクセスしたいと考えています。攻撃者が最初に確認できることは、アプリケーションが通常のペンテスト技術によって悪用できるかどうかです。例えば、SQLmapを使えば、攻撃者はデータへのアクセスを試みることができます。

しかし、これがうまくいかない場合、次のステップは何でしょうか?

攻撃者は、コンテナに脆弱な依存関係があるかどうか、使用されているイメージが悪用される可能性があるかどうかを確認し、コンポーネントまたはノード自体が悪用可能かどうかを確認することができます。しかし、すべてがうまくいっているように見えます。CVEマッチもなく、初期アクセスに使用できる既知のエクスプロイトもありません。

次はどうする?さて、Prometheusは攻撃者がアクセスしたイメージとレジストリを公開しましたが、サプライチェーンへの攻撃はどうでしょうか?この場合、2つのシナリオが考えられます。

  • Official/private registration: この場合、攻撃者は、同音異義語など、異なるユニコードグループを使用することで視覚的に類似したイメージ名を使用し、ターゲットを騙すことができます。また、内部関係者を悪用して、公開されたイメージを手動で変更させるという手法も考えられます。この場合、攻撃者の金銭的な利益に依存します。
  • Third-party registry この場合、BeeFのようなツールを使って特定のフィッシングページや偽ページを作成し、ログイン認証情報を取得して、既知の悪用可能な脆弱性を持つ新しいイメージに変更し、デプロイメントを待つというソーシャルエンジニアリングの手法が考えられるでしょう。もう一つ、これは魔法でもなければ100%成功するわけでもありません。もし企業がデプロイされたイメージをスキャンすれば、検出される可能性があります。

クリプトマイニング

このシナリオは、クラウド時代のここ数年で最も関連性の高いものの1つです。攻撃者は、アプリケーションやKubernetesクラスターがデプロイされているクラウドアカウントにアクセスすることを望んでいます。攻撃者は2つの経路を取ることができます。一つは、Ingress-controllerを介して公開されているアプリケーションのうち、HTTP経由で簡単に悪用できる既知の脆弱性を持つものを特定し、コンテナ内でリモートコード実行を取得する方法です。

このケースで悪用される脆弱性は、悪名高いlog4shellです。

攻撃者がコンテナにアクセスできれば、クラスターやノードに関する情報をさらに収集する必要すらなくなりますが、これはPrometheusがこれらの情報も公開しているためです。そこから、別の脆弱性を直接悪用してコンテナにエスケープし、さらにツールやスキャンを使用せずにノードにフルアクセスし、典型的な防御方法を回避することができるのです。

注:これは100%成功するわけではありません。ランタイムセキュリティが使用され、コンテナ内のシェルが悪意のある動作として検出された場合、リソースに影響を与える前にインシデントを検出することができます。

これで攻撃者はノードを完全に制御できるようになり、クリプトマイナーを実行するためのコンテナをデプロイしたり、設定ファイルや環境変数からクラウド認証情報を見つけて初期アクセス権を獲得したりできるようになります。

Attacker path exploit Kubernetes Cluster by exposed Prometheus server
しかし、これは遠回りです。近道は何でしょう?Prometheusでは、かつてのKubernetes Dashboardと同じように、これらのクラウドプロバイダーに対して直接クレデンシャルを公開することが可能です。したがって、攻撃者はクエリーで情報を照会し、平文でAPIキーを取得するだけでよいのです。

ランサムウェア

そう、Kubernetesにおけるランサムウェアは典型的なものではないですが、不可能ではありません。シナリオは先程と似ています。書き込みアクセスを取得する必要があり、そのためにはネームスペース間をジャンプしたり移動したりする必要があります。

この場合、Spring Cloudという異なる脆弱性を持つ別のアプリケーションを見つけますが、目的は同じです:コンテナ内でシェルを取得することです。

コンテナ内にシェルがある場合、Kubernetesのコンポーネントが古い脆弱なバージョンであることがわかり、それを悪用してetcdにアクセスし、それによってネームスペースにフルアクセスすることができるのです。

ここで不思議なのは、データが暗号化された後、攻撃者は何らかの経路で身代金を要求する必要があることです。典型的なシナリオでは、私たちのPCはロックされ、画面にはBTCまたはETH経由で支払う指示が表示されますが、コンテナ内では、そのようなことはありません。悪者とアイデアを共有するのは嫌ですが、1つの選択肢として、修正したUIを持つコンテナをデプロイし、実際のアプリケーションの前にこれを表示するようにingressに強制することができます。

まとめ

セキュリティの観点からはメトリクスは重要でないと考えるかもしれませんが、そうではないことを実証しました。KubernetesPrometheusは、データを世界に公開することの問題を助言しますが、それとは関係なく、これらの問題はまだ広まっています。

私たちのチェーンのすべての部分でセキュリティベストプラクティスに従うことは、ほとんどのセキュリティインシデントから安全であることにつながります。そうでなければ、攻撃者と防御者の長い戦いがある典型的なシナリオを、スピードランのために変更することになります。

Kubernetes threats speedrun

私たちのサービスに影響を与える新たな脆弱性と、インサイダーに対する計画とも戦い続けなければならないでしょう。しかし、少なくとも彼らにとっては困難な状況を作り出しましょう。




Sysdigは、これらの情報をあなたの指先に置くことで、Kubernetesのトラブルシューティングをはるかに容易にします。Sysdig Monitorの無料トライアルに登録し、業界をリードするKubernetesモニタリング製品ですぐに詳細な情報を入手しましょう。