Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Secur0 Academy — Web CTF Challenges

Home for web CTF challenges built for Secur0 Academy. Every challenge follows one shared contract so it deploys identically on Docker today and Kubernetes later — without rebuilding the challenge.

What's here

Path What it is
requisites.md The authoring spec. Every rule (MUST) a challenge has to satisfy. Read first.
challenge-template/ Copy-paste starter. Working skeleton pre-wired to pass the spec.
<your-challenge>/ One folder per challenge (add your own).

Authoring a new challenge

  1. Read the specrequisites.md. The whole platform relies on the contract: challenge reads config from the environment and exposes one port it does not choose itself.

  2. Copy the template:

    cp -r challenge-template my-challenge
    cd my-challenge
  3. Fill it in — find every placeholder and replace:

    grep -rn "REPLACE\|replace-me" .

    Swap in your vulnerable app (src/), metadata (challenge.yml), docs (README.md), and the solution (solution/). Pin the base image digest in Dockerfile / docker-compose.yml.

  4. Run it locally:

    cp .env.example .env
    docker compose up --build
    curl http://localhost:8080/healthz   # -> ok
  5. Tick every box in the challenge's CHECKLIST.md. It maps 1:1 to the spec — a challenge is accepted only when all boxes pass.

The contract in one breath

A challenge talks to the platform through only three things:

  • PORT — internal port it binds (0.0.0.0, never a fixed host port)
  • FLAG — injected at runtime, opaque, never baked into the image
  • GET /healthz — returns 200 when ready to serve

Everything else — host port mapping, per-student isolation, TTL, flag injection — lives in the platform, never in the challenge. That's why the same image runs unchanged under docker compose or Kubernetes.

Rules that trip people up

  • Never commit .env or a real flag. Only .env.example is committed.
  • No fixed host port in committed files — use ${HOST_PORT}.
  • One public port per challenge; databases/caches stay internal.
  • Non-root, no privileged, pin the base image by exact tag or digest.
  • Flag must be unreachable without the intended exploit.

Full detail and the reasoning behind each rule: requisites.md.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages