THM — Jumpbox

EtcSec
7 min readSep 9, 2022

Platform: TryHackMe
Room: Jumpbox
Difficulty: Hard
Tags: Security, Kubernetes
Description: How are your parkour skills?

Attack System:
Kali Linux / Current

Download your connection pack and connect to the VPN:

$ sudo openvpn <username>.ovpn

Just like last time, I know very little about Kubernetes. The first time I finished this room it took about 6–7 hours, spread across two days. I am re-doing this box for the write up, to hopefully keep the read a bit more coherent than my notes are.
You’d think that I’d know a little more about Kubernetes by now…

This box needed a little bit of extra time to start up, so I gave it 10 minutes before I started. Aside from that, this box was very responsive, and pleasant to work with.
To the creator: Thank You!

The first thing I did was run an nmap scan to get an idea what I could poke at on the box. For the write-up, I left out -sC just to keep the output smaller. Using -sC does show that port 8443 is running Kubernetes, so if you’re following along, I recommend using -sC with your nmap scan.

What came back from the nmap scan was port 22(SSH), 80(HTTP), and 8443(ssl/https-alt).

Output snip from the nmap scan with -sC option

The next thing I did was take a look to see what the GoTTY service on port 80 was. It was pretty cool, it was shell in the browser, something I’d rarely seen done so well before.

The next thing I did was set up a temporary folder to work out of in /tmp/temp and transfer in files that I might want to use.
The files I transferred in were:
DeepCE (sourced from GitHub)
LinPEAS (sourced from GitHub)
kubectl (sourced locally)

There seemed to be a firewall in place, so I had to transfer the files over a “standard” port. In my case, port 53(DNS) worked just fine.

First I ran deepce to see what it could find. I wasn’t really was excited about the results as deepce didn’t find anything “juicy”. The best thing I saw was that curl, wget, and nc were available for use.

The next thing I ran was linpeas. There was a lot of output, but one thing really caught my eye, a reference to the service account. If there is only one thing I know about Kubernetes, it’s that you need a token to do anything.

Knowing that I’d be needing this, I set it to a local environment variable so I could use it easier.

Before going any further, I wanted to get an idea of what other containers were running. Even though ping was installed, it required root privileges to run it. I grabbed a static copy of nmap and transferred it over so I could run a ping sweep with it.
To make things easier on myself, I also added /tmp/temp to the path.

The nmap ping sweep came back with 4 IPs in the range of 172.17.0.1–172.17.0.10

Ok, 4 boxes, time to flush them out so I know what I’m working with. Fun fact- ALL the containers are on the same machine, so a -p- scan doesn’t take but a second to run.

Docker host? Kubernetes brain? Which is it? No idea.

Now that I had a better idea of where I was, I wanted to see what all pods were running. This was easy since I had already transferred kubectl over.

I’m not sure if kubectl is statically compiled by default, of if what it needs was already there. It worked, so I just went with it.

There was one particularly interesting pod- “jumpbox-admin”.

I want that jumpbox-admin container, but I needed to know what permissions the service account token had. I ran kubectl with the token I had found and passed auth can-i --list to it to see what permissions I had with the token. Of note, I had get & create permissions to nodes/proxy.

I wanted to know if this would let me “get” jumpbox-admin? Maybe there would be some useful information that I could get from it?

I highly recommend using this: Kubernetes Cheat Sheet

Didn’t seem to be of much use… I read a bunch of Kubernetes docs and stuff, and ended up back on the “official” Cheat Sheet page again. In the Viewing and Finding Resources block, I saw what I was looking for. If you pass -o yaml along with get pod you can get the pods yaml file. This is what I went for next, there had to be something useful in it.

Perfect, the yaml. Quite a chunk of output though… I found some bits in the yaml that I thought might come in handy.

{"uid":"27718ff3-220b-4060-95ea-05a756d80b4b"}{"name":"ubuntu"}{"ip":"172.17.0.4"}manager: kubeletimage: ubuntu:latestimagePullPolicy: IfNotPresentimageID: docker-pullable://ubuntu@sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae

Next, remembering that the service account token had get/create permissions, I tried to fire up a bad pod. I modified the “Everything-Allowed” Bad Pod with adjustments from the jumpbox-admin yaml output above, specifically the imageID.

Too Bad — So Sad. I was denied.

Guess I’m gonna need an admin token.

I looked back at my “network map” and wanted to know some more about the higher ports on the docker host (172.17.0.1). What I found was pretty interesting, check these out:

I was relieved to find something “juicy”.

I tried to hit the API with something based on the above, to see if it was there. I got a response “Unauthorized”, good! This meant that the API was there. I just needed a…token :)

So, I tried it again, with the service account token. I got a response of “404: Page Not Found”. Looks like progress to me :)

The container name from the yaml data was “ubuntu”, so I tried to tack that onto the end of the request. OK! Great! I got back “command exited with 126:” Looks like solid RCE to me :)

Obviously, the next thing I did was send a command, id. Guess what? It responded in the most wonderful way possible:

uid=0(root) gid=0(root) groups=0(root)

Assuming that the directory structure would be the same, I checked for a service account token at /run/secrets/kubernetes.io/serviceaccount/token

It was there. So sent the request again and sent the output to a file, new.token; this was then set to the environment variable NEW_TOKEN.

Next up, I wanted to see what permissions the “new token” had. Guess what? It had all of them, like Full Control.

Alright, everything is set, time to own this box…or not.
UGH!

Looks like that image name was bad… Gotta find another one.
Back to the Kubernetes Cheat Sheet

I went back and edited the correct image name into my yaml file and tried to start the pod up again. Phew, it worked that time.

Now, finally, the easy part.

kubectl exec --token=$NEW_TOKEN -it mypod -- chroot /host bash

Thats it.
Done.
No, I do not like Kubernetes.

Happy Hacking!!

--

--