Skip to content

Challenges

Below, we go through the challenge format, including the structure of the challenge, the expected files, and the expected content of these files.

Challenge Format

A challenge should have at least the following files and directories:

  • challenge.toml is a TOML file that contains all the metadata for the challenge.
  • README.md is a markdown file that contains an informal overview of the challenge;
  • Source/, which contains all the source files for the challenge;
  • Handout/, which contains all the files that are given to the contestants;

Additionally, Tests/ and/or Build/ directories may be present, where the Tests/ directory contains any tests for the challenge, and the Build/ directory contains any build scripts for the challenge.

The challenge directory itself should be put in a category directory of the desired category, see Categories for more detail.

challenge.toml

The challenge.toml file describes all the needed metadata for the challenge, for both the running and presenting of the challenge. The following fields are supported in the challenge.toml file:

UUID

The first line of the challenge.toml file should be a UUIDv4, as this is used to uniquely identify the challenge. On linux, you can generate a random UUIDv4 with the command uuidgen.

[5da55141-2f35-4822-91b5-fd28e1686d09]
# rest of file
Name

The name of the challenge, this is what will be displayed to the contestants on the CTF platform.

name = "Example Challenge"
Flag

The flag for the challenge, with an assigned static point value.

flag = { "FLAG{example_flag}" = 100 }
Difficulty

The difficulty of the challenge, usually limited to "easy", "medium", and "hard".

difficulty = "medium"
Description

The description of the challenge, this is what will be displayed to the contestants on the CTF platform.

description = """Example description line1
Example description line 2"""
# or
description = """Example description single line"""
URL

The connection string of the challenge, as e.g. http://{{IP}}:{{PORT}} or nc {{IP}} {{PORT}}. It should contain {{IP}} and {{PORT}} placeholders that will be replaced with the actual IP or URL and port when the challenge is run.

Optional The URL field should be omitted if the challenge doesn't need to be run.

url = "http://{{IP}}:{{PORT}}"
Instanced

A boolean value indicating whether the challenge is instanced.

Optional This field should be omitted if the challenge is not instanced, and and defaults to false. challenge is instanced.

instanced = true
Hints

A list of hints for the challenge with their point cost, shown on the CTF platform.

Optional If omitted, no hints will be shown for the challenge.

hints = { "Example hint 1" = 10, "Example hint 2" = 20 }
Hidden

A boolean value indicating whether the challenge is hidden. Hidden challenges are not shown to contestants on the CTF platform, but are still deployed.

Optional This field should be omitted if the challenge is not hidden, and defaults to false.

hidden = true
Dynamic Flag

TODO

Optional Defaults to false.

dynamic_flag = true
Tags

A list of tags for the challenge, shown on the CTF platform.

Optional If omitted, no tags will be shown for the challenge.

tags = ["example"]

Example challenge.toml

[1457f303-0894-42c9-bd06-484e92d8fc5d]
name = "Example"
flag = { "FLAG{example_flag}" = 100 }
difficulty = "medium"
description = '''
This is an example challenge.
'''
url = "nc {{IP}} {{PORT}}"
instanced = true
hints = { "Try harder" = 10 }
# hidden, dynamic_flag, and tags are omitted in this example

README.md

The README contains an informal overview of the challenge, including any important deployment information, design notes, high-level solution, and other considerations. This may contain sensitive information.

Source Directory

This directory contains all the needed source files for the challenge, this is where the Dockerfile and any other server hosted code should be.

Default Deployment

By default, the checker.py program will attempt to build, run, and destroy the challenge purely off the Dockerfile in the source folder. This means that, if your challenge has a Dockerfile that works with a simple docker build and docker run command, you don't need to add any additional scripts to the source folder, and the checker.py will handle the deployment for you based on the format specified in the challenge.toml.

Of course, as specified in the challenge.toml section, if your challenge doesn't need to be run then you just omit the url field in the challenge.toml file.

Additional deployment configuration

However, if you require additional deployment configuration, you can add two scripts to the source folder, run.sh and destroy.sh.

run.sh

The run.sh should be a shell script that handles the running of the challenge. The run.sh script is called as follows:

run.sh --hostname HOSTNAME --port PORT --flag FLAG --registry REGISTRY
HOSTNAME

HOSTNAME is the hostname that will be provided to the players, this may be an IP or DNS address.

PORT

PORT is the port where the challenge is to be run. Note that, whilst the invoking checker.py bears the responsibility of the port being available, run.sh is responsible for ensuring the port is accessible on the provided hostname.

FLAG

FLAG is an optional argument that passes the flag specified in the challenge.toml to the run.sh script, this can be used to deploy dynamic flags. If your challenge does not support dynamic flags, you can simply ignore this argument and deploy the static flag as specified in the challenge.toml.

REGISTRY

REGISTRY is a docker registry that should be used to push any built images to, in case docker service is supported.

destroy.sh

The destroy.sh is a shell script that ensures the deployment is destroyed. The script should exit silently with code 0 if a deployment is successfully destroyed, and print any errors and throw a tantrum otherwise.

Handout Directory

This is what gets given to the contestants, all files in this folder are zipped and then distributed.

Build Directory

TODO

Tests Directory

TODO