# circus-companion The companion ~cube~ container spawned specifically for one user. ## Purpose - Validator for flags - Temporary secret vault for the user - control endpoint of challenge containers for the user ## Usage This executable needs some parameters to work properly: | Key | Required? | Description | |---|---|---| | `-port` | No | The port for HTTP. *Default: 8080* | | `-username` | No | Name of our user, as used e.g. in salutation. No length or charset limitation. *Default: Player 1* | | `-accessCode` | Yes | Access code for the user. *Default: AllYourCodesAreBelongToUs* | | `-sessionSalt` | Yes | Variable to salt the session token generator with. | | `-seedFile` | Yes | JSON file to read challenge information from. | | `-vpnRemoteAddress` | Yes | Address the VPN will run on, as rendered into the client VPN configuration file. | | `-vpnRemotePort` | No | Port the VPN will run on | | `-endTimestamp` | No | Date/Time after which flags are not accepted anymore | | `-endAfter` | No | Seconds (!) after the first login, after which flags are not accepted anymore | If `-endTimestamp` **and** `-endAfter` is given, flags are not accepted if **one** of the given flags kicks in. ## Seed file The seed file should be of the following format: ``` { "challenges": [ { "name": "Evil Service", "description": "A meaningful and funny description", "flag": "CIRCUS[IS_REALLY_COOL]", "container": "challenge-evilservice", "category": "Miscellaneous", "points": 100 }, { "name": "Insecure Stuff", [...] ] } ``` ## API endpoints | Path | Method | Parameter | Description | |---|---|---|---| | `/` | GET | - | static hosting `/files/index.html` | | `/files/{file}` | GET | - | static hosting `{file}`, from `hosted/` directory. *Path traversal*-safe | | `/login` | GET | - | static hosting `/files/login.html` | | `/login` | POST | `username`, `accesscode` | processing `username` and `accesscode`, giving the user a session if they are valid | | `/logout` | GET | - | Invalidates the session | | `/challenges` | GET | - | static hosting `/files/challenges.html` | | `/access` | GET | - | static hosting `/files/access.html` | | `/api/getChallenges` | GET | - | Returns all challenges, as JSON. For an example, see below. | | `/api/submitFlag` | POST | `challengeName`, `flag` | Validates `flag` for `challengeName` | | `/api/startContainer` | POST | `challengeName` | Starts the challenge container for `challengeName`, if it's not already started | | `/api/stopContainer` | POST | `challengeName` | Stops the challenge container for `challengeName`, if it's running | | `/api/getAccess` | GET | - | Returns the VPN configuration required for accessing the containers | ### Response: `/api/getChallenges` ``` { "categories": { "Miscellaneous":1 // contains the amount of challenges in that category }, "challenges": [ { "name": "ChallengeName", "description": "Some meaningful, interesting and funny description", "category": "Miscellaneous", "points": 100, "foundFlag": false, // whether the user found the flag "ContainsLaunchable": true, // if set to true: there's a container which can be started/stopped "IPAddress": "1.2.3.4" // contains the IP address if the container is running } ] } ```