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
}
]
}