A Simple CTFd Plugin (not really a plugin) that will act as a flag generator and validator
NOTE: This only works with challenges that have a RegEx-based Flag and works only on TEAM Mode (along with the containers plugin)
The working of this is as follows:
- Creating an API using FastAPI and exposes two endpoints:
-
/flag
- This API takes two query parameters:team_id
chal_id
And generates a FLAG based on these parameters.
-
/check
- Runs a check against the submitted flags and those in the database to check for duplicates.
- Also checks if someone without generating a flag, submitted it.
-
Each team will have a single flag for a single challenge and that flag will be stored locally in
flags.db
file.
- Team-A generates a flag, Team-B submits it before Team-A
(Both teams will be banned)
- Team-B generated a flag, Team-A submits it, Team-B doesn't submit
(Both teams will be banned) [Each team will have 1 flag generated per challenge, and that won't change no matter how many new instances are spawned]
- Team-A somehow guesses the Regex and generates a flag and submits it
(Team-A will be banned for brute-forcing and not solving as intended)
- Team-A and Team-B banned for using Team-A's flag. Team-C submit's Team-A's flag
(Team-C will be banned)
CTFD_ADMIN_TOKEN
- The CTFd API Administrator TokenCTFD_INSTANCE
- The URL for the CTFd InstanceDISCORD_WEBHOOK_URL
- [OPTIONAL] - The Webhook URL to post your Ban notifications on Discord (by default, Notifications are posted on CTFd as well.)API_HOST
- [DEFAULT: 0.0.0.0] - The host on which the API will listen onAPI_PORT
- [DEFAULT: 9125] - The port on which API will listen onVERIFICATION_DELAY
- [DEFAULT: 1] - The delay (in minutes), after which request to/check
will be made.DB_NAME
- [DEFAULT: flags.db] - The local database name in which flags and their detail will be stored
In order to integrate this with your CTFd docker-compose
, just copy the following config into your CTFd's docker-compose:
flagvalidator:
build: . # Change this to the folder you have the source code + Dockerfile in.
ports:
- "172.17.0.1:9512:9512"
environment:
- CTFD_ADMIN_TOKEN=
- CTFD_INSTANCE=
- DISCORD_WEBHOOK_URL=""
- API_HOST="0.0.0.0"
- API_PORT=9512
- VERIFICATION_DELAY=1
- DB_NAME="flags.db"
volumes:
- .:/app/
restart: always
Make sure that you paste this under the
services
key inside thedocker-compose.yml
.
In order to set this up, we need to run this inside docker. Both Dockerfile and docker-compose.yml have been provided to make it easier. The flags.db
will be generated at run time and the current folder will be mounted inside the docker container.
NOTE: If you're running a local
CTFd
deployment, make sure to modify the variables inside your docker-entrypoint scripts accordingly.
Let's suppose we have a challenge called test_chal
, and we want to add a dynamic flag. The YAML config file is:
name: "test_chal"
author: "TheFlash2k"
category: Test
description: Some Descriptive Description
value: 100
type: container
extra:
initial: 100
decay: 1
minimum: 100
image: test_chal:latest
port: 8000
command: ""
volumes: ""
build: ./src/
flags:
- {
type: "regex",
content: "CY243L{s4mpl3_fl4g_r3geX_[0-9a-zA-Z]{9}[1-9a-zA-Z]{9}[5-9a-eR-Z]{8}",
data: "case_insensitive",
}
state: visible
version: "0.1"
Now, inside the src/
folder, a Dockerfile can be as follows:
FROM php:7.0-apache
ENV BASE_DIR="/var/www/html"
COPY ./src/ $BASE_DIR/
COPY ./docker-entrypoint.sh /
RUN echo "ServerName localhost" >> "/etc/apache2/apache2.conf"
ENTRYPOINT [ "/docker-entrypoint.sh" ]
Now, inside the docker-entrypoint.sh
, we need to fetch the flag from http://172.17.0.1:9152
(or whatever your API_PORT is)
NOTE: The IP is of
docker0
interface on your system
Quick Fact: Using the
containers
plugin which I've forked, I setCHALLENGE_ID
andTEAM_ID
as environment variable on each container being deployed, therefore, the script uses these:
service=http://172.17.0.1:9512
flag=$(curl -s $service/flag\?chal_id\=$CHALLENGE_ID\&team_id\=$TEAM_ID)
# We now have the flag in $flag and can do whatever we want:
echo $flag > /var/www/html/flag.txt
Similarly, for your own containers, you will have to write a similar docker-entrypoint.sh
and set that as your entrypoint to cater for dynamic flaging. The rest will be managed by this plugin.