SMCTF: CTF Platform for everyone, specialized for SMCH1
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.
See SMCTF Docs for more details. This README only provides a brief overview.
- AuthN/AuthZ (JWT), including registration keys management
- Challenge management (Jeopardy CTF style, See
ctf_service.gofor 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)Ref Issue: #18, PR: #19- Frontend has been moved to a separate repository (nullforu/smctfe)
- Challenge file upload/download support via AWS S3 Presigned URL
- Per challenge individual Stack(instance/VM) provisioning support via Kubernetes
- Ref PR: #25, See container-provisioner-k8s and docs for more details.
- ... and more! (See docs for more details)
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.
- Backend: Go, Gin, Bun ORM
- Container Provisioner: Go (nullforu/container-provisioner-k8s)
- Frontend: React (nullforu/smctfe)
- Database, Cache: PostgreSQL(instead of MySQL/MariaDB), Redis
- Testing: Testcontainers for Go
- Infra: AWS, EKS, Helm, Terraform, Cloudflare, etc. (See nullforu/smctf-infra for more details)
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 .envAnd 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=15mImportant
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/serverNote
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.
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:
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.pyYou can also use the wrapper script:
./scripts/generate_dummy_sql.shTemplates 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.yamlCLI options:
--data: path to data YAML (users/teams/challenges). Defaults to bundleddata.yaml.--settings: path to settings YAML. Merged over defaults. Defaults to bundledsettings.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 keyshigh_solve_rate.yaml: increase solve probability and attempt countslow_solve_rate.yaml: decrease solve probability and attempt countsfew_attempts.yaml: lower number of attempts per usermany_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.sqlDefaults 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.
(Not yet)
See SMCTF Docs for more details.
This project is licensed under the MIT License. See the LICENSE file for details.
| Name/GitHub | Role | Affiliation |
|---|---|---|
| @yulmwu | Main maintainer | Semyeong Computer High School, Null4U |
... and more Null4U members.

