Hack The Box: Steam Cloud
What will you learn? Steam Cloud is an easy difficulty retired machine as part of the cloud learning track for Hack The Box. This is a great introduction to penetration testing with Kubernetes and recognizing container security issues that attackers leverage. The Kubelet service allows for anonymous access which allows attackers to extract a list of running pods in the K8 cluster. The ability to enumerate the pods vulnerable to remote code execution via a service account can let an attacker reach sensitive tokens / certificates. These combined can lead to the creation of a malicious pod that attackers can use to reach the contents of other pods from their remote location using those mentioned command line utilities.
Let’s begin enumerating the target:
We find some ports open 22 (SSH), and many Kubernetes ports: ETCD client/server (2379 and 2380). Then Kubelet which is a Kubernetes extension listening on port 10250 and Kubernetes API is on port 8443.
The Kubernetes API (Application Programming Interface) can not be accessed without valid authentication, so we cannot enumerate that. This we can confirm when trying to reach the port 8443 hosting the API saying anonymous access is not allowed.
We can use curl against the port hosting Kubelet, a Kubernetes extension, and extract all of the pods from the cluster. The cluster being a group of nodes running applications, and the pods being a group of one or more containers - in this case, we’re really just acquiring a list of containers we could potentially target/enumerate.
We can use the KUBELETCTL command line utility to interface with the API and discover a means to get inside one of the pods from the list via the cluster we extracted. Download and equip the binary into your working path: https://github.com/cyberark/kubeletctl
This utility will let us retrieve a listing of all of the pods, their namespace, and the container they’re running in. It is interesting to note that the default namespace is running with NGINX which is not a Kubernetes related pod.
We are able to use the commands /run
, /exec
, and /cri
but curl will not work because it only allows web socket connections.
We are able to use a command to test against the pod list to see where we can run commands, with the scan rce
command set. This shows us that we have remote code execution against the pod kube-proxy-kjshf
and nginx
.
When we have remote code execution against a pod we can run commands using the exec
parameter with the pod and namespace specified. Here we can run id
among other commands to enumerate the container which tells us we’re running as the root user.
Since we’re able to run commands, as a privileged user too, we can go to common file locations to retrieve an access token and certificate. These will allow us to use Kubectl and see what kind of permissions we have.
Now we can save the certificate inside a file called ca.crt and export the token as an environmental variable which will enable us to obtain a list of pods.
Running the command to return a list of pods only shows us one. So we can then enumerate the permissions this service account has too. This tells us we can acquire, list, and create in a default namespace.
Running the command below will give us the important information of the NAMESPACE and IMAGE TYPE, which we will embed into a YAML file.
Knowing that we can create in the default namespace. We can create a malicious pod using a YAML configuration file containing our near-unique specifications. The mount path is important as that and the path mentioned below at /
define from where and what we’re going to be accessing when we try to reach the original container.
Now with our YAML file ready we can deploy it by using KUBECTL’s apply function. Creating a new pod that can access the other, and we can verify its status as running as a second matter. Now we can use KUBELETCTL to interact with our newly stood up container and navigate to that /mnt
path where the path to the other machine should be in the cluster.
Now we can retrieve the user and root flags on the other Kubernetes pod through starting our directory pointing in /mnt
and diving deeper from there.