Vamos a realizar una segunda enumeración para obtener más información:
Vemos el puerto 5000 , con la información dada podemos ver que se trata de una web creada en Python. Vamos a darle un vistazo a la aplicación web:
Vemos un inicio de sesión podríamos probar credenciales típicas como:
admin:admin
administrator:administrator
test:test
Pero nada de esto funcionará. Vemos otra opción que es para registrarnos, veamos que tal:
Ya que tenemos la oportunidad vamos a crearnos una cuenta:
Shell as aidor
Vemos que nos hizo una redirección a /dashboard . Ojeando vemos que no hay grandes funciones en la aplicación web. Pero me llamó la atención una cosa:
Vemos el parámetro id, donde nos otorga el número 56. Podríamos probar a cambiar el número a uno más bajo a ver si estamos ante un IDOR y podemos acceder al panel de otro usuario:
Vemos que ahora estamos en el panel del usuario aidor . Así que estamos ante un IDOR, viendo su panel me encuentro lo siguiente:
Vemos que podemos cambiarle la contraseña o copiar el hash de la actual, vamos a intentar crackearlo con crackstation:
Vemos que la contraseña del usuario aidor es chocolate. Vamos a probarla por SSH:
Shell as root
Enumerando encontré lo siguiente:
Vemos el archivo database.db vamos a ver su contenido:
Vamos a enumerar las tablas:
Vamos a obtener todas las columnas de la tabla a ver su contenido:
Vemos unos cuantos usuarios y su respectiva contraseña en hash. Antes de empezar a hacer fuerza bruta vamos a leer el /etc/passwd para ver que usuarios existen:
No vemos ningún usuario que coincida en la base de datos. Vamos a leer el app.py :
┌──(pylon㉿kali)-[~/…/pylon/Dockerlabs/Aidor/nmap]
└─$ nmap -p22,5000 -sCV 172.17.0.2
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-21 19:25 CET
Nmap scan report for 172.17.0.2
Host is up (0.000051s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 10.0p2 Debian 7 (protocol 2.0)
5000/tcp open http Werkzeug httpd 3.1.3 (Python 3.13.5)
|_http-server-header: Werkzeug/3.1.3 Python/3.13.5
|_http-title: Iniciar Sesi\xC3\xB3n
MAC Address: 02:42:AC:11:00:02 (Unknown)
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 6.46 seconds
┌──(pylon㉿kali)-[~]
└─$ ssh aidor@172.17.0.2
aidor@172.17.0.2's password:
Linux 7fa1aaff0355 6.16.8+kali-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.16.8-1kali1 (2025-09-24) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Nov 21 18:39:37 2025 from 172.17.0.1
aidor@7fa1aaff0355:~$
aidor@7fa1aaff0355:/home$ ls -la
total 52
drwxr-xr-x 1 root root 4096 Nov 21 18:32 .
drwxr-xr-x 1 root root 4096 Nov 21 17:19 ..
drwx------ 1 aidor aidor 4096 Nov 21 17:55 aidor
-rw-r--r-- 1 root root 4862 Nov 17 14:59 app.py
-rw-r--r-- 1 root root 24576 Nov 21 18:32 database.db
drwxr-xr-x 2 root root 4096 Nov 17 14:52 templates
aidor@7fa1aaff0355:/home$ sqlite3 database.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite>
aidor@7fa1aaff0355:/home$ cat /etc/passwd | grep sh
root:x:0:0:root:/root:/bin/bash
aidor:x:1000:1000:aidor,,,:/home/aidor:/bin/bash
sshd:x:995:65534:sshd user:/run/sshd:/usr/sbin/nologin
app.py
from flask import Flask, render_template, request, redirect, url_for, session, flash
import sqlite3
import hashlib
import os
app = Flask(__name__)
app.secret_key = 'my_secret_key'
# Ruta para conectar a la base de datos
def get_db():
conn = sqlite3.connect('database.db')
return conn
# Crear la base de datos y la tabla si no existen
def create_db():
if not os.path.exists('database.db'):
conn = get_db()
cursor = conn.cursor()
# Crear la tabla de usuarios si no existe
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
email TEXT NOT NULL
)
''')
# Insertar un usuario de ejemplo si la tabla está vacía
cursor.execute('SELECT COUNT(*) FROM users')
count = cursor.fetchone()[0]
# if count == 0:
# cursor.execute('''
# INSERT INTO users (username, password, email) VALUES
# ('root', 'aa87ddc5b4c24406d26ddad771ef44b0', 'admin@example.com')
# ''') # La contraseña "admin" es hash SHA-256
conn.commit()
conn.close()
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# Hash de la contraseña
hashed_password = hashlib.sha256(password.encode()).hexdigest()
conn = get_db()
cursor = conn.cursor()
cursor.execute('SELECT * FROM users WHERE username=? AND password=?', (username, hashed_password))
user = cursor.fetchone()
conn.close()
if user:
session['user_id'] = user[0] # Guardar el ID del usuario en la sesión
# Redirigir al dashboard con el ID en la URL
return redirect(url_for('dashboard', id=user[0]))
else:
return 'Usuario o contraseña incorrectos', 401
return render_template('index.html')
# Página de registro
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
email = request.form['email']
password = request.form['password']
# Hash de la contraseña
hashed_password = hashlib.sha256(password.encode()).hexdigest()
conn = get_db()
cursor = conn.cursor()
# Verificar si el usuario ya existe
cursor.execute('SELECT * FROM users WHERE username=?', (username,))
existing_user = cursor.fetchone()
if existing_user:
return 'El usuario ya existe', 400
# Insertar el nuevo usuario en la base de datos
cursor.execute('''
INSERT INTO users (username, password, email) VALUES (?, ?, ?)
''', (username, hashed_password, email))
conn.commit()
# Obtener el ID del usuario recién creado
cursor.execute('SELECT id FROM users WHERE username=?', (username,))
new_user = cursor.fetchone()
conn.close()
if new_user:
session['user_id'] = new_user[0]
return redirect(url_for('dashboard', id=new_user[0]))
return render_template('register.html')
# Página de dashboard con parámetro id en la URL
@app.route('/dashboard')
def dashboard():
# Obtener el ID de la URL o de la sesión
user_id = request.args.get('id') or session.get('user_id')
if not user_id:
return redirect(url_for('index'))
conn = get_db()
cursor = conn.cursor()
cursor.execute('SELECT * FROM users WHERE id=?', (user_id,))
user = cursor.fetchone()
conn.close()
if not user:
return redirect(url_for('index'))
# Actualizar la sesión con el ID del usuario
session['user_id'] = user[0]
return render_template('dashboard.html', user=user)
# Ruta para cambiar contraseña
@app.route('/change_password', methods=['POST'])
def change_password():
if 'user_id' not in session:
return redirect(url_for('index'))
user_id = session['user_id']
new_password = request.form['new_password']
# Hash de la nueva contraseña
hashed_password = hashlib.sha256(new_password.encode()).hexdigest()
conn = get_db()
cursor = conn.cursor()
cursor.execute('UPDATE users SET password=? WHERE id=?', (hashed_password, user_id))
conn.commit()
conn.close()
return redirect(url_for('dashboard', id=user_id))
# Ruta de logout
@app.route('/logout')
def logout():
session.pop('user_id', None)
return redirect(url_for('index'))
if __name__ == '__main__':
create_db() # Llamamos a la función para crear la base de datos al iniciar la app
app.run(debug=True, host='0.0.0.0', port=5000) # Especificamos el puerto 5000
# if count == 0:
# cursor.execute('''
# INSERT INTO users (username, password, email) VALUES
# ('root', 'aa87ddc5b4c24406d26ddad771ef44b0', 'admin@example.com')
# ''') # La contraseña "admin" es hash SHA-256
aidor@7fa1aaff0355:/home$ su
Password:
root@7fa1aaff0355:/home# whoami
root