cmgr is a new backend designed to simplify challenge development and
management for Jeopardy-style CTFs. It provides a CLI (cmgr
) intended for
development and managing available challenges on a back-end challenge server
as well as a REST server (cmgrd
) which exposes the minimal set of commands
necessary for a front-end web interface to leverage it to host a competition
or training platform.
Assuming you already have Docker installed, the following code snippet will
download example challenges and the cmgr binaries, initialize a
database file that tracks the metadata for those challenges, and then run the
test suite to ensure a working system. The test suite can take several minutes
to run and is not required to start working. However, running the suite can
identify permissions and other errors and is highly recommended for the first
time you use cmgr
on a system.
wget https://github.com/ArmyCyberInstitute/cmgr/releases/latest/download/examples.tar.gz
wget https://github.com/ArmyCyberInstitute/cmgr/releases/latest/download/cmgr_`uname -s | tr '[:upper:]' '[:lower:]'`_amd64.tar.gz
tar xzvf examples.tar.gz
cd examples
tar xzvf ../cmgr_`uname -s | tr '[:upper:]' '[:lower:]'`_amd64.tar.gz
./cmgr update
CMGR_LOGGING=info ./cmgr test --require-solve
NOTE: If you are running this on an ARM-based computer, you will need to change amd64
in the cmgr tarball to arm64
.
At this point, you can start checking out problems by finding the challenge ID
of one you would like to play and running ./cmgr playtest <challenge>
. This
will build and start the challenge and run a minimal webserver (localhost:4200
by default) that you can use to view and interact with the content. You could
also launch the REST server on port 4200 with ./cmgrd
or launch all of the
examples from the CLI with ./cmgr test --no-solve
which will launch an
instance of each example challenge and print the associated port information.
cmgr is configured using environment variables. In particular, it currently uses the following variables:
-
CMGR_DB: path to cmgr's database file (defaults to 'cmgr.db')
-
CMGR_DIR: directory containing all challenges (defaults to '.')
-
CMGR_ARTIFACT_DIR: directory for storing artifact bundles (defaults to '.')
-
CMGR_LOGGING: logging verbosity for command clients (defaults to 'disabled' for
cmgr
and 'warn' forcmgrd
; valid options aredebug
,info
,warn
,error
, anddisabled
) -
CMGR_INTERFACE: the host interface/address to which published challenge ports should be bound (defaults to '0.0.0.0') (Note: if the specified address is not bound to the host running the Docker daemon, this value gets silently ignored by Docker and the exposed ports will be bound to the loopback interface.)
-
CMGR_PORTS: the range of ports that are dedicated for serving challenges; cmgr will assume that it fully owns these ports and nothing else will try to use them (i.e., not in ephemeral range or overlapping with a service running on the host); format is '1000-1000'. Ephemeral ports on a Linux host can be enumerated with
cat /proc/sys/net/ipv4/ip_local_port_range
and adjusted withsysctl
. Some programs (e.g.,docker
) will need to be restarted after adjusting the kernel parameter. -
CMGR_ENABLE_DISK_QUOTAS: enables the disk quota container option when set. Disk quotas are only functional when using the
overlay2
Docker storage driver and pquota-enabled XFS backing storage. Otherwise, the creation of containers with disk quotas will fail at runtime. When unset, any specified quotas are ignored.
Additionally, we rely on the Docker SDK's ability to self-configure base off environment variables. The documentation for those variables can be found at https://docs.docker.com/engine/reference/commandline/cli/.
One of our design goals is to make developing challenges for CTFs as simple as possible so that developers can focus on the content and not quirks of the platform. We have specific challenge types that make it as easy as possible to create new challenges of a particular flavor, and the documentation for each type and how to use them are in the examples directory.
Additionally, we have a simple interface for creating automated solvers for
your challenges. It is as simple as creating a directory named solver
with
a Python script called solve.py
. This script will get its own Docker
container on the same network as the instance it is checking and start with
all of the artifact files and additional information provided to competitors in
its working directory. Once it solves the challenge, it just needs to write
the flag value to a file named flag
in its current working directory and
cmgr will validate the answer and report it back to the user.
In both the challenge and solver cases, we support challenge authors using
custom Dockerfiles to support creative challenges that go beyond the most
common types of challenges. In order to support the other automation aspects
of the system, there are some requirements for certain files to be created
during the build phase of the Docker image and are documented in the custom
challenge type example.
Testing challenges is meant to be as easy as executing cmgr test
from the
directory of an individual challenge or the directory containing all of the
challenges for an event. This is intended to support quick feedback cycles
for developers as well as enabling automated quality control during the
preparation for an event.
Another design of this project is to make it easier for custom front-end
interfaces for CTFs to reuse existing content/challenges rather than forcing
organizers to port between systems. To make this possible, cmgrd
exposes a
very simple REST API which allows a front-end to manage all of the important
tasks of running a competition or training environment. The OpenAPI specification
can be found here.
If you're interested in contributing, modifying, or extending cmgr, the
core functionality of the project is implemented in a single Go library under
the cmgr
directory. You can view the API documentation on
go.dev.
Additionally, the SQLite3 database is intended to function as a read-only
API and its schema can be found here.
In order to work on the back-end, you will need to have Go installed and cgo enabled for at least the initial build where the sqlite3 driver is built and installed. To get started, you can run:
git clone https://github.com/ArmyCyberInstitute/cmgr
cd cmgr
go get -v -t -d ./...
mkdir bin
go build -v -o bin ./...
go test -v ./...
This project is heavily inspired by the picoCTF platform and seeks to be a next generation implementation of the hacksport back-end for CTF platforms built in its style.
Please carefully read the NOTICE, CONTRIBUTING, DISCLAIMER, and LICENSE files for details on how to contribute as well as the copyright and licensing situations when contributing to the project.