Skip to content
/ smctf Public

A Jeopardy CTF(Capture The Flag) platform optimized for easy initial configuration

License

Notifications You must be signed in to change notification settings

nullforu/smctf

Repository files navigation

SMCTF: CTF Platform for everyone, specialized for SMCH1


SMCTF Preview SMCTF Preview

About

SMCTF2 is a CTF platform developed by Null4U, a DevOps and Cloud Computing club at Semyeong Computer High School (SMCH).

When hosting CTF competitions within school security clubs such as SCA, we faced several challenges:

  • Using existing open source CTF platforms involved a steep learning curve.
  • They required complex initial configurations, such as plugins for provisioning individual instances or VMs for each challenge.
  • Existing platforms were provided only as container images or source code, requiring us to design an architecture tailored to our infrastructure.
  • We also found that logging, monitoring, and user management features were insufficient.

As a result, we decided to develop our own CTF platform as a long term project. We are releasing it as an open source project so that it can be used in various CTF competitions.

Features

See SMCTF Docs for more details. This README only provides a brief overview.

Available/Stable features:

  • AuthN/AuthZ (JWT), including registration keys management
  • Challenge management (Jeopardy CTF style, See ctf_service.go for a list of categories.)
  • Flag submission with rate limiting and HMAC verification
  • Scoreboard and Timeline (Redis caching support)
  • User profile with statistics (Some implementations are still WIP)
  • Logging middleware with file logging, structured JSON logging and OpenMetrics endpoint support
  • User and Team management (WIP)
  • Dynamic scoring (ref: CTFd - Dynamic Value)
  • UI customization and detailed configuration options (WIP)
  • Challenge file upload/download support via AWS S3 Presigned URL
  • Per challenge individual Stack(instance/VM) provisioning support via Kubernetes
  • ... and more! (See docs for more details)

Planned/Upcoming features:

Also, the following features are planned to be implemented. see issues for more details.

  • (WIP) Systematized admin dashboard and behavior log/monitoring system integration
  • ... and more features to be added.

Tech Stacks

Installation and Usage

See docs for more details. This README only provides a quick start guide.

Note

PostgreSQL and Redis are required. if necessary, use Docker to run them locally. (for development/testing purposes only)

docker compose -f docker-compose.db.yaml up -d

# if `app_db` database does not exist, create it:
PGPASSWORD=app_password psql -U app_user -d postgres -h localhost -c "CREATE DATABASE app_db;"

If you need a remote DB server, refer to the configuration values ​​in docker-compose.db.yaml. tables, indexes, etc. will be automatically migrated when the server starts.

git clone https://github.com/nullforu/smctf.git
cd smctf

touch .env

And add the following environment variables to .env file (refer to .env.example):

APP_ENV=production
HTTP_ADDR=:8080
SHUTDOWN_TIMEOUT=10s
AUTO_MIGRATE=true
# ... (other variables)
Click to expand .env.example file content. (default values)
# App
APP_ENV=local
HTTP_ADDR=:8080
SHUTDOWN_TIMEOUT=10s
AUTO_MIGRATE=true
BCRYPT_COST=12

# PostgreSQL
DB_HOST=localhost
DB_PORT=5432
DB_USER=app_user
DB_PASSWORD=app_password
DB_NAME=app_db
DB_SSLMODE=disable
DB_MAX_OPEN_CONNS=25
DB_MAX_IDLE_CONNS=10
DB_CONN_MAX_LIFETIME=30m

# Redis
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_POOL_SIZE=20

# JWT
JWT_SECRET=change-me
JWT_ISSUER=smctf
JWT_ACCESS_TTL=24h
JWT_REFRESH_TTL=168h

# Security
FLAG_HMAC_SECRET=change-me-too
SUBMIT_WINDOW=1m
SUBMIT_MAX=10

# Cache
TIMELINE_CACHE_TTL=60s
LEADERBOARD_CACHE_TTL=60s

# Stack (Container Provisioner)
STACKS_ENABLED=true
STACKS_MAX_PER_USER=3
STACKS_PROVISIONER_BASE_URL=http://localhost:8081
STACKS_PROVISIONER_API_KEY=change-me
STACKS_PROVISIONER_TIMEOUT=5s
STACKS_CREATE_WINDOW=1m
STACKS_CREATE_MAX=1

# Logging
LOG_DIR=logs
LOG_FILE_PREFIX=app
LOG_MAX_BODY_BYTES=1048576

# Bootstrap
BOOTSTRAP_ADMIN_TEAM=true
BOOTSTRAP_ADMIN_USER=true
BOOTSTRAP_ADMIN_USERNAME=admin
BOOTSTRAP_ADMIN_EMAIL=
BOOTSTRAP_ADMIN_PASSWORD=

# S3 Challenge Files
S3_ENABLED=false
S3_REGION=ap-northeast-2
S3_BUCKET=
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_ENDPOINT=
S3_FORCE_PATH_STYLE=false
S3_PRESIGN_TTL=15m

Important

Make sure to change JWT_SECRET and FLAG_HMAC_SECRET to secure random strings in production!

After setting up the environment variables, build and run the server:

git clone https://github.com/nullforu/smctf.git

go mod download
go build -o smctf ./cmd/server
./smctf

# or: go run ./cmd/server

Note

Running in Docker environment will be supported in the future.

Logging Schema

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "SMCTF Log Event",
    "type": "object",
    "additionalProperties": true,
    "required": ["ts", "level", "msg", "app"],
    "properties": {
        "ts": {
            "type": "string",
            "format": "date-time",
            "description": "RFC3339 timestamp with timezone"
        },
        "level": {
            "type": "string",
            "enum": ["debug", "info", "warn", "error"]
        },
        "msg": { "type": "string" },
        "app": { "type": "string" },
        "legacy": { "type": "boolean" },
        "error": {},
        "stack": { "type": "string" },
        "http": {
            "type": "object",
            "additionalProperties": true,
            "properties": {
                "method": { "type": "string" },
                "path": { "type": "string" },
                "status": { "type": "integer" },
                "latency": { "type": "string" },
                "ip": { "type": "string" },
                "query": { "type": "string" },
                "user_agent": { "type": "string" },
                "content_type": { "type": "string" },
                "content_length": { "type": "integer" },
                "user_id": { "type": "integer" },
                "body": { "type": "string" }
            }
        }
    }
}

Currently, please use local installation for development and testing. Requires Go and NodeJS, NPM installation.

Testing

To run the tests, use the following command:

go test -v ./internal/...
# or with race detector, coverage options
go test -v -race -cover -coverprofile=coverage.out ./internal/...

Check the Codecov report for test coverage:

Dummy/Sample SQL Data

For testing purposes, you can populate the database with dummy data using the following script:

# python3 -m pip install -r ./scripts/generate_dummy_sql/requirements.txt
python3 ./scripts/generate_dummy_sql/main.py

You can also use the wrapper script:

./scripts/generate_dummy_sql.sh

Templates and YAML inputs are supported:

chmod +x ./scripts/generate_dummy_sql.sh

./scripts/generate_dummy_sql.sh --list-templates
./scripts/generate_dummy_sql.sh --template team_only.yaml --template high_solve_rate.yaml
./scripts/generate_dummy_sql.sh --data ./scripts/generate_dummy_sql/defaults/data.yaml --settings ./scripts/generate_dummy_sql/defaults/settings.yaml

CLI options:

  • --data: path to data YAML (users/teams/challenges). Defaults to bundled data.yaml.
  • --settings: path to settings YAML. Merged over defaults. Defaults to bundled settings.yaml.
  • --template: template YAML to apply before settings (repeatable).
  • --output: override output SQL file path.
  • --seed: random seed for reproducible output.
  • --list-templates: list bundled templates.

Available templates:

  • solo_only.yaml: force users to have no team (no team join / no team assignment for registration keys)
  • team_only.yaml: force users to always join a team and assign team on registration keys
  • high_solve_rate.yaml: increase solve probability and attempt counts
  • low_solve_rate.yaml: decrease solve probability and attempt counts
  • few_attempts.yaml: lower number of attempts per user
  • many_attempts.yaml: higher number of attempts per user

This will generate a dummy.sql file. You can then import this file into your PostgreSQL database:

# for docker-compose.db.yaml
PGPASSWORD=app_password psql -U app_user -d app_db -h localhost -f dummy.sql

Defaults live in ./scripts/generate_dummy_sql/defaults/ and can be overridden with your own YAML. It provides sample challenges, 30 users (including admin), and random submissions data from the last ~48 hours.

Warning

This will TRUNCATE all tables in the database! Use only in development/test environments.

FAQ, Troubleshooting

(Not yet)

See SMCTF Docs for more details.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributors

Name/GitHub Role Affiliation
@yulmwu Main maintainer Semyeong Computer High School, Null4U

... and more Null4U members.

Footnotes

  1. SMCH: Semyeong Computer High School (세명컴퓨터고등학교)

  2. SMCH(SMC) + CTF = SMCTF

About

A Jeopardy CTF(Capture The Flag) platform optimized for easy initial configuration

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •  

Languages