DCTF is a Docker-based CTF platform that is used to deploy (currently) binary and web(flask) challenges in a docker container.
- python>=3.5
- pip
- docker
- docker-compose
- ruamel.yaml
Note: To satisfy all pip dependencies run
sudo pip install -r requirements.txt
.
Quickly building and bringing the CTF up is as simple as running a single command.
python ctf.py -bus
This builds the docker images, brings the CTF up using the newly generated docker-compose.yml
file, and prints the status of the challenges. More information on this below.
Connecting to localhost:10000
with netcat, we can see that our binary is being served within the docker container on the specified port.
Navigating to localhost:10001
with our browser, we can see that our flask app is running perfectly.
usage: ctf.py [-h] [-b] [-u | -d] [-f] [-s] [-r] [--platform PLATFORM]
[--update]
Docker-based CTF Platform
optional arguments:
-h, --help show this help message and exit
-b, --build build the docker images
-u, --up start the CTF
-d, --down stop the CTF
-f, --fly deploy new challenges on the fly
-s, --status displays the status of the challenges
-r, --remove remove all ctf containers and images
--platform PLATFORM install ctf frontend [CTFd/FBCTF]
--update update the docker compose config
The build
flag parses the YAML files that are paired with every challenge and runs the ./scripts/gen.sh
script with the proper arguments according to the type of the challenge.
After the gen.sh
script finishes, build
calls the build
script in the skel
directory which builds the appropriate docker image.
The up
flag calls the update
function to get an up to date list of all of the challenges and then calls docker-compose up -d
to start the challenges in the background.
The down
flag calls docker-compose down
.
The fly
flag calls build
, then update
, and then docker-compose up -d
. This is a quick and dirty solution without having to mess with figuring out what is up and what isn't.
The status
flag calls docker-compose ps
.
The remove
flag parses the INI files that are paired with every challenge and runs the ./scripts/delete.sh
script with the name of each challenge in order to delete all challenge-related containers and images.
Once all containers and images are removed, remove
calls ./scripts/remove.sh
which removes all directories matching *-build
in the main directory. After removing all build directories, it calls docker network prune -f
to forcibly remove unused docker networks.
The platform
flag currently allows you to generate config files for FBCTF. Future plans will be to allow for CTFd and NIZKCTF.
The update
flag has no short option. It is used as a manual way of updating the docker-compose.yml
file. It parses all YAML files in the challenge directories and builds the docker-compose.yml
file based on the name of the challenge and the ports it runs on.
The config.yml
file is a very important file. It is necessary to include one in every challenge folder. Without this, the platform doesn't know what to call your challenge or what port it runs on. The use of the config.yml
file was to give the naming conventions of challenges as much leeway as possible.
Below is the sample config.yml
file for foo-bin
:
1. Foo Bin Challenge:
2. title: foo
3. description: Binary challenge example.
4. category: pwnable
5. flag: FLAG{PLACEHOLDER_FLAG}
6. points: 10
7. port: 10000
8. serve: true
9. hint: ""
The challenge title can be anything. This is to help identify the challenge to the author.
The title of the challenge must be within [A-Za-z0-9._-]
. This is a requirement per the Docker specification. Docker image names may not stray from this.[1]
Note: If there is a binary being served, it must be the same name.
The description can be anything. It is only used when generating FBCTF config files.[1]
The type of challenge is required. There is one special challenge category that is web
. If the category of the challenge is web
, then the platform will look for a file called app.py
in the root of the challenge folder. This is used to serve a Flask website. Everything else (binary
, crypto
, re
, etc.) will be treated as a binary challenge.[1]
The flag is not required, but it is used to help easily identify the flag of the challenge.[1]
The points are not required, but it is used as a reference.[1]
The port number is required if you have serve set to true. This is the local port that your challenge will be served on.[1]
Serve can either be 'true' or 'false'. This depends on whether or not you want the challenge to be run by Docker. This can be used to create multiple challenges under the same Docker container.
The hint is required if you want to generate valid FBCTF configs. If your challenge does not need a hint, simply put two quotation marks.[1]
[1] If you want to generate an FBCTF config file with --platform
, this is required.
The most barebones config.yml
would be as follows:
Foo Bin Challenge:
title: foo
category: pwnable
port: 10000
serve: true
Note: This is not compliant with FBCTF as it does not have a hint field, however the DCTF platform will be able to handle the creation of a docker container to serve this challenge.