Skip to content

Repository files navigation

CTF Workspace

A reusable, self-contained workspace for solving Capture-the-Flag challenges: a sandboxed analysis toolbox, an MCP-driven autonomous solver suite (Claude + Codex), a consistent per-challenge folder structure, a curated reference library, and an archive of solved challenges with their writeups (Markdown only).

Lineage: Grey Cat 2026 Quals (archived) → BoroCTF training run (archived) → SekaiCTF 2026 (concluded 2026-06-29; the event the solver suite was built for and folded into this repo) → Grey Cat 2026 Finals (concluded; wrapped up + archived 2026-07-01) → No Hack No CTF 2026 + R3CTF 2026 (concluded 6 Jul 2026) → Junior.Crypt 2026 (GRODNO::CTF; concluded 2026-07-12, wrapped 2026-07-20). Each competition's flag format + rules live in its own competitions/<comp>/README.md.

Everything needed to triage, solve, verify, and document a challenge lives in this one repo. The only things you install are Docker/Colima and the Python virtualenvs — brought up by the sandbox/ scripts; the sandbox itself is boot-on-ask (it starts the VM on first use).


What's in this repo

  • sandbox/ — a Dockerized, amd64 analysis toolbox (ctftools) plus its scripts. Boot-on-ask: sandbox/box <dir> starts Colima on first use and drops you into a fresh container with the challenge mounted at /work; sandbox/reap/halt clean up. Host toolchains (Ghidra, .NET, Foundry, …) come from source sandbox/env.sh. The install-*.sh set builds the host venvs + per-category tooling.
  • toolkit/ — the host-side solver machinery: reference search (refsearch, semantic + lexical), the deterministic triage extractor (static tier prior; re-tiered from the Sweep's real outcomes, ADR-0033), the cost governor, the multi-session launcher, the platform-adapter (intake), plus solver helpers (pow.py, coppersmith_fast.sage, run-timeout), Ghidra headless scripts, and challenge-folder templates.
  • mcp/ — the MCP servers: our sandbox-exec server (run_in_sandbox — the only blessed exec path — + verify_flag, the nonce gate that structurally prevents reporting an unverified flag), alongside vendored, audited analysis servers (radare2, slither, headless pyghidra, frida).
  • competitions/<comp>/ — one folder per challenge, the live status board, and the solved-challenge archive (each solved challenge carries its full writeup set).
  • reference/ — a curated library: per-category resources, accumulated lessons, worked practice solves, an archive of authored challenges, and imported public writeups — searchable from one command.

Two safety rules (repo etiquette)

  1. Don't attack the competition platform / scoreboard — no exploitation, auth bypass, DoS, scanning, brute force, or messaging organisers. Intake is fine (reading descriptions + downloading handouts). Flag submission follows each comp's flag_submission toggle (default: the operator submits). Connecting to a challenge's own service (its nc host:port, its web app) to solve it is the whole point and is always fine.
  2. Run untrusted challenge code and binaries only inside the sandbox, never on the host. CTF artifacts are hostile by default — that is exactly what the disposable container is for (structurally enforced by the run_in_sandbox MCP tool).

Repository layout

The actual on-disk workspace layout. As of 2026-07-03 the AI operating layer is now published (agent team, architecture, docs, playbooks); runtime state, large/regenerable trees, and machine-specific config stay local (gitignored) — flagged [local] below.

.
├── CLAUDE.md · AGENTS.md · ARCHITECTURE.md · CONTEXT.md   # operating guides · system design (L0–L9b) · glossary
├── .claude/                       # Claude harness — agents/ (15 specialists) · skills/ · hooks/ · rules/   (settings*.json [local])
├── .codex/                        # Codex twins — agents/*.toml · hooks/   (config.toml + hooks.json [local])
├── .agents/                       # generated skills mirror (for Codex)
├── docs/                          # component deep-dives (agents/sweep/governor/triage/launcher/platform/…) + ADRs 0001–0037 + archive/
├── competitions/
│   ├── junior-crypt-2026/          # Junior.Crypt 2026 — concluded, wrapped 2026-07-20 (40 solved · 9 stuck)
│   ├── r3ctf-2026/                # R3CTF 2026 — concluded 6 Jul (1 solved · 12 stuck)
│   ├── nhnc-2026/                 # No Hack No CTF 2026 — concluded 6 Jul (27 solved · 5 stuck)
│   ├── greycat-2026-finals/       # concluded — archived 2026-07-01 (19 solved · 13 stuck)
│   ├── sekaictf-2026/             # concluded event — README (toggles), STATUS board, challenges/
│   ├── greycat-2026-qualifiers/   # archived reference event
│   └── boroctf/                   # archived training run
│       └── challenges/{<Category>/<slug>/, solved/<Category>/<slug>/}
├── sandbox/                       # boot-on-ask amd64 toolbox — box/reap/halt · setup.sh/install-*.sh · Dockerfile[.ml] · env.sh · INSTALLED.md
├── toolkit/                       # the solver machinery:
│   ├── triage / governor / launch / solve-wave / sweep     # tier prior · cost control · multi-session launcher · autonomous sweep (ADR-0033)
│   ├── stall-guard / auto-steer / compose-prompt / finalize-stale   # anti-grind lane-switch + loop hygiene
│   ├── prune-artifacts / audit-challenge   # lean-after-solve prune + folder-conformance
│   ├── platform-adapter / coordinator      # CTFd/rCTF/manual intake (+ optional poll-and-solve, off)
│   ├── refsearch / rag / gen-status / gen-codex-mirror / lint-* / check-manifest / pow.py / coppersmith_fast.sage / run-timeout
│   └── ghidra_scripts/ · templates/        # headless Ghidra scripts · meta.yml/README/solve.py/writeup scaffolds
├── mcp/
│   ├── sandbox_exec/server.py     # our MCP: run_in_sandbox + verify_flag (+ checksec/disasm/…)
│   └── vendor/ [local]            # audited third-party servers (radare2 / slither / pyghidra / frida)
├── reference/                     # curated library — playbooks/ published; corpus/writeups/wordlists/.rag [local]
├── README.md · .gitignore
│
└── [local] on disk, gitignored, NOT published:
    ├── .venv/                     # unified solver+AI host venv (pwntools/angr/z3/sage/torch/… — rebuilt by sandbox/install-*.sh)
    ├── tools/                     # host-native toolchains (~1.3G: Ghidra/.NET/Foundry/… — reinstalled, not tracked)
    ├── .models/ · pyghidra-projects/ · .governor/ · .launch/   # local models · Ghidra projects · runtime state & caches
    └── .mcp.json · .claude/settings*.json · .codex/{config.toml,hooks.json} · competitions/*/{.env,.token}   # machine config + secrets

Quickstart

# 1. One-time: build the toolbox image + host venvs + per-category tooling.
./sandbox/setup.sh           # then the install-*.sh lanes as needed (host / sage / ghidra / ai)
source sandbox/env.sh        # put host toolchains on PATH (or add to ~/.zshrc)

# 2. Drop into the toolbox with a challenge mounted at /work (boots Colima on first use).
sandbox/box competitions/sekaictf-2026/challenges/<Category>/<slug>

# 3. Inside the container — analyze the binary, debug, exploit:
checksec ./binary
qdb ./binary          # debug: native ptrace is blocked under Rosetta -> qdb uses qemu-user's gdbstub

# 4. Search the curated reference library from the host for prior art / techniques.
toolkit/refsearch coppersmith
toolkit/refsearch -c pwn "tcache poisoning"

The sandbox / toolbox

The host is Apple-Silicon macOS (arm64), but CTF challenge binaries are almost always x86-64 Linux. They run inside an amd64 Colima VM (Docker engine, VZ + Rosetta) so the emulation is fast. The VM is boot-on-asksandbox/box (and the run_in_sandbox MCP tool) start it on first use; there is no manual bring-up step.

Two Apple-Silicon gotchas, both worked around in-house:

  • Rosetta blocks ptrace → native gdb can't debug an emulated amd64 binary. Use qdb inside the toolbox (qdb ./binary), which debugs via qemu-user's gdbstub. Running/exploiting stays on Rosetta (fast); debugging uses qemu (works, slower).
  • Rosetta SIGILLs FLINT's large-multiply (AVX) kernel → Sage's small_roots / defund crash on big polynomials. Use the cop-run/msolve-wrap qemu wrappers in the sandbox, or toolkit/coppersmith_fast.sage natively (which dodges FLINT entirely for univariate Coppersmith).

Surfaces: ctftools (the everyday amd64 toolbox image, built from sandbox/Dockerfile) + ctftools-ml (a heavy-ML layer, on demand) + host .venv (the unified native-arm64 venv: pwntools, angr, z3, cvc5, OR-Tools, pycryptodome, sympy, … + the AI suite — torch, fickling, picklescan, ART, …) + a host SageMath miniforge env. Each sandbox/box call is a fresh docker run --rm container — nothing persists, so add anything reusable to the Dockerfile and rebuild.

Full tool manifest and teardown: sandbox/INSTALLED.md.


Per-challenge folder convention

Each challenge lives in challenges/<Category>/<slug>/ (category-first; <Category> = the organiser's label for this comp):

  • meta.yml — a rigid, closed 6-field schema (linter-enforced, no prose), in order: name, category (the organiser's per-competition label — not a fixed global list, see CONTEXT.md), status (new | solving | solved | stuck), tier (T0T4), flag, solved_by (user | teammate, required only when solved). No timestamps (ADR-0012).
  • README.md — 4 sections (Challenge · Handout · Analysis · Dead ends); Challenge + Handout required, the rest optional (ADR-0013).
  • handout/ — the given files, treated as read-only.
  • solve/ — per-attempt folders attempt-<harness>-NN/ (harness ∈ claude | codex | gpt), each with a findings.md. One attempt = one solve session by one driver; a fan-out's subagents are internal to that one attempt.
  • On a verified solve the folder gains writeup/archive/ (the detailed Markdown writeup, always produced) and — per the comp's submission_writeup toggle — writeup/submission/ (the short organiser ticket). .tex/.pdf render retired (ADR-0003).

Active work stays under challenges/<Category>/<slug>/; on a verified solve the folder is archived (slug unchanged) under challenges/solved/<Category>/<slug>/, so the active listing always equals the remaining work. Provenance lives in meta.yml solved_by: + STATUS.md, not the path.


How a challenge flows

Intake (build the folder from the platform-adapter / templates) → triage (the deterministic extractor sets a low-biased tier prior) → re-tier (the Sweep's real session/attempt outcomes set the tier, ADR-0033) → solve (a specialist works an attempt folder; untrusted code runs only in the sandbox; heavy compute is detached via the governor) → self-verify (the verify_flag nonce gate; the candidate flag goes in meta.yml while status stays solving, and the operator is pinged) → operator confirms acceptance (status → solved) → writeups (Archive always, Submission per toggle) → archive the folder + regenerate STATUS.md.

Commit etiquette: the default is to edit in place and never commit — the tree may be shared by parallel drivers (Claude + Codex, even on the same challenge), isolated by per-attempt folders, with append-only shared files. Commit/push only when the operator explicitly asks.


Competition status & solved index

Verified solves under challenges/solved/<Category>/<slug>/ carry the Markdown Archive Writeup (writeup/archive/, always) and — per submission_writeup — the Submission Writeup (writeup/submission/); meta.yml solved_by: records who landed each.


Reference library

A curated, searchable library of prior art: reference/README.md (the category-first index) · reference/playbooks/ (per-discipline cheat sheets) · reference/resources.md · reference/lessons.md.

toolkit/refsearch <query...>             # search all of reference/ (semantic, lexical fallback)
toolkit/refsearch -c crypto <query...>   # narrow to one category

Setup & environment

Prerequisites: macOS on Apple Silicon (arm64) · Colima + Docker CLI (the amd64 VM, VZ + Rosetta) · a host python3 for the venvs.

Bring-up: ./sandbox/setup.sh (idempotent — builds the ctftools image + host .venv), then the sandbox/install-*.sh lanes (host solvers, SageMath, Ghidra, AI suite, the P2.5 per-category tooling) as needed. Re-run setup.sh to rebuild after editing the Dockerfile. Full teardown: sandbox/INSTALLED.md.

Regenerated, not committed (gitignored): the host .venv/ (unified — solver stack + AI suite), large host-native tools under tools/ (e.g. Ghidra), the reference/ corpus + RAG index, and oversized challenge handouts (memory dumps / multi-GB images, ignored case-by-case and noted in each challenge's README.md).

About

Private CTF workspace — sandboxed toolchain, agent team, curated reference. Grey Cat 2026.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages