Skip to content

Latest commit

 

History

History
74 lines (59 loc) · 2.49 KB

File metadata and controls

74 lines (59 loc) · 2.49 KB

CTFd Structure

Configuration

The build script looks for a config.yml in the root of the ctf directory. All configuration options within this file will be submitted to CTFd.

---  
config:  
  ctf_theme: core-beta  
  user_mode:  users  
  account_visibility: private  
  score_visibility: private  
  registration_visibility: private  
  registration_code: private by design  
  paused: 1  
  ctf_name: "{{ CONFIG_ACCOUNT.title() }} CTF"  
  ctf_description: "Capture the Flag event hosted by Lacework for {{ CONFIG_ACCOUNT }} on the {{ CONFIG_SUBACCOUNT }} subaccount. Scope includes the following AWS accounts: {{ CONFIG_AWS_ACCOUNTS }}"  

Categories

Every directory within this ctf directory will become a category. Prefix with a number_ for sorting purposes. i.e. 1_getting to know you

Challenges

Inside of each category directory create a challenges.yml with the challenge structure. The field structure follows what the CTFd API expects.

---
challenges:
- name: compliance
  value: 5
  type: standard
  state: visible
  description: |
    description text
  flags:
  - type: static
    data: case_insensitive
    content: private by design

- name: oh really?
  value: 100
  type: standard
  connection_info: 'https://memecentral.org/wp-content/uploads/2019/08/really-seriously-meme.jpg'
  description: |
    Do you believe the user account **{{ CONFIG_AWS_USER }}** is problematic?  Why or why not?
  flags:
  - type: regex
    content: .*

Global built in variables

Any variable passed in via a config.json will be made available in all YAML files. The variable will be uppercased and then prefixed with CONFIG_ Examples below.

aws_account becomes CONFIG_AWS_ACCOUNT account becomes CONFIG_ACCOUNT subaccount becomes CONFIG_SUBACCOUNT

parse_challenge function

To make the challenge descriptions and flags dynamic you can add a parse_challenge function into a __init__.py file in the category directory. Each challenge for that category will be passed through this function. Example function signature below. schema argument is an import of schema as a module. challenge argument is the JSON of the challenge object. config is the passed in config.json

def parse_challenge(schema, challenge, config):
    # modify challenge details
    # add flag(s) to challenge
    challenge['flags'] = []
    flag = { 'type': 'static', 'data': 'case_insensitive', 'content': 'flag goes here' }
    challenge['flags'].append(flag)
    return challenge