WEBVERSE

Loading...

Halcyon FM
hardFree

Halcyon FM

Halcyon FM is a listener-supported community radio station with a public site and a staff playout console. A rival station somehow got hold of an unaired script and the underwriter list. Trace the path in.

ssrfinternal-api-exposureswagger-disclosurecommand-injectionbroken-access-controlinsecure-deserializationpython-picklerceinformation-disclosure
pythonflaskgunicornpostgresnginx

The Scenario

Halcyon FM is a small listener-supported community station up in Asheville. Marlow and a rotating crew of volunteers run the whole thing off a couple of machines in the back of the studio. The public site carries the schedule and takes show pitches. The playout console the crew use to run automation lives on its own subdomain.

Last week an unaired pledge-drive script and the station's underwriter contact list turned up, word for word, on a rival station's blog. Nobody on the crew can explain how anyone reached the console. Start on the public site as an anonymous listener and find the way through to whatever is running the back office.

Lab Intel

Synopsis

Halcyon FM spans a public station site, a staff playout console on its own subdomain, and an internal ops API bound to the web container's 127.0.0.1:8080 that the gateway never exposes. A full-read SSRF in the public 'pitch a show' preview reaches that loopback API. The preview reports only reachability by default, but the request carries an is_dev flag that, when set true, reflects the full fetched body. With is_dev on, the loopback API's swagger enumerates a user dump, a POST-only change-password, and a command-injection stream probe. The GET-only SSRF pivots through the command injection to POST the admin's new password, then the pickle-based playlist import on the console turns into RCE and reads the flag.

Architecture

A hard multi-service lab on four containers (nginx gateway, a Flask public site that also runs the internal ops API on its own loopback, a Flask staff console, and Postgres). The chain is SSRF to a loopback internal API, swagger-driven recon, an account dump, a command-injection bridge (the ops API's 'is the stream mount live' check shells out to curl with an unsanitised stream_url), and a Python pickle insecure-deserialization RCE. It is deliberately defense-in-depth: the command injection gives code execution in the WEB container as the opsapi user, but the flag lives at /home/halcyon/flag.txt in the STUDIO container, so cmdi alone cannot read it. The cmdi is only a bridge that lets the GET-only SSRF issue a local POST to the POST-only change-password endpoint. The only path to the flag is taking over the admin account, logging into the console, and abusing its 'Import playlist' pickle.loads sink, which runs as the halcyon user. change-password rejects GET with 405, the ops API is loopback-only and never routed by the gateway, and the DB credentials are scrubbed from both web processes so the command injection has to pivot via curl rather than a direct database connection.

Who It's For

Built for intermediate to advanced testers comfortable chaining a server-side request forgery into backend exploitation. You should understand SSRF against internal services, reading an OpenAPI spec to enumerate an API, shell command injection, and Python pickle deserialization to RCE. No out-of-band listener is needed, the whole chain is in-band.

Skills You'll Practice

  • Server-side request forgery against a loopback-bound internal service
  • Enumerating a self-describing API from its status root and swagger.json
  • Chaining a GET-only SSRF through a command-injection endpoint to reach a POST-only action
  • Shell command injection via an unsanitised diagnostics parameter
  • Python pickle insecure deserialization to command execution

What You'll Gain

  • Why an internal API bound to loopback is not safe when a co-located service has an SSRF
  • How a self-documenting internal API becomes the attacker's map
  • Recognising that RCE on one host does not mean RCE on the host with the secret
  • Turning an 'import your own export format' feature into a pickle RCE

Ready to hack Halcyon FM?

This lab is free. Sign up and start hacking.