Skip to content

Redesign challenges for unique skills; fix hints, docs and test tooling - #133

Merged
madebygps merged 10 commits into
mainfrom
fix/challenge-docs-hints
Sep 29, 2026
Merged

madebygps merged 10 commits into
mainfrom
fix/challenge-docs-hints

Conversation

@madebygps

@madebygps madebygps commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Reviews the challenge catalogue for real skills, correct setup, accurate docs/hints, and no bad practices. Each challenge now teaches one distinct skill and tool.

Docs and hints

  • Fixed inaccurate hints and README rows for ch2, 5, 10 and 12.
  • Rewrote hints (verify/src/verify/commands.py) and README rows for every changed challenge.

Challenge changes

  • 3: 5 MB auth log with one odd Accepted line to find among 50,000 Failed lines
  • 4: flag in a service account's GECOS field
  • 5: chmod a mode-000 key pointed to by a world-writable config
  • 8: real SSH key auth as vault (password login disabled, flag printed by ForceCommand)
  • 9: custom search domain via resolved.conf.d, resolve host with getent hosts
  • 11: fix both the nginx listen port and the typo'd root
  • 12: no more hex leak via logs
  • 13: cron job writes the flag to a status log from a root-only file
  • 14: flag loaded through EnvironmentFile=, no longer in systemctl show/cat
  • 15: nested gz, bz2, xz archives (installs bzip2 and xz-utils)
  • 16: three-link chain; the flag is the final filename, not file contents
  • 17: flag hidden in a 400-line shell history
  • 18: flag is the ext4 volume label (blkid/e2label)

Test tooling

  • The solver in .github/skills/ctf-testing/ covers the new challenges.
  • deploy_and_test.sh: after an AWS stop/start the public IP changes, so it now asks EC2 for the new one.
  • test_ctf_challenges.sh: sync before reboot (GCP hard-resets and its root fs uses commit=30, which lost the reboot marker; reproduced 3/3 without sync, 0/3 with it). The ch9 solver also no longer matches Azure's own internal.cloudapp.net domain.

Testing

Full deploy_and_test.sh <provider> --with-reboot passes on AWS, GCP and Azure (28 solver checks + 6 post-reboot checks, 0 failures each), all run against the final test scripts.
Also verified by hand on a live AWS VM as ctf_user: ch8 password login is rejected, and the old shortcuts (cat, systemctl show/cat, /proc/PID/environ, grep -a on the ch15 archive) no longer expose flags. Broad grep -r 'CTF{' can still find some plain-text flags; that is accepted.

Notes

  • Removed the inbound port 8083 rules from the three main.tf files. The nginx listener on 8083 in ch11 is only reached from the VM, so nothing needs it exposed. Full test with reboot re-run on all three clouds afterwards: PASS.
  • A hard reset within 30 s of a solve can lose a learner's progress on GCP (commit=30). Not addressed here.

madebygps and others added 8 commits September 29, 2026 07:38
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 713688f7-85cd-404d-92fe-f94163885359
Update setup, hints, README and test solver accordingly; install bzip2/xz-utils
for ch15 and restart systemd-resolved for ch9.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 713688f7-85cd-404d-92fe-f94163885359
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 713688f7-85cd-404d-92fe-f94163885359
GCP resets the VM without a clean shutdown, which lost the reboot marker.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 713688f7-85cd-404d-92fe-f94163885359
Nginx's misconfigured listener on 8083 is only reached from the VM in ch11,
so no cloud needs to expose it. Full test with reboot passes on AWS, Azure
and GCP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 713688f7-85cd-404d-92fe-f94163885359
Move connect, capture flags, verify commands and finish steps into GUIDE.md,
add a quick start to the root README, and simplify the AWS region steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7ca812f-6f5f-4846-b188-475430b77721
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7ca812f-6f5f-4846-b188-475430b77721
Make nginx directive edits fail clearly on unexpected templates, centralize learner artifact ownership, scope history-file ownership, and clarify the cron challenge description.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 80c0c0ee-bd2b-41fb-804d-9b865e59da2c
@madebygps

Copy link
Copy Markdown
Collaborator Author

Follow-up from the challenge setup review: commit 9ea3e65 adds the agreed cleanup.

  • Fails clearly when challenge 11 cannot find exactly one expected original or already-modified nginx directive, instead of silently skipping replacements.
  • Clarifies challenge 13 wording so it matches the persistent cron output.
  • Centralizes final ctf_challenges ownership after all challenge setup modules run, removing the unrelated dependency from challenge 18.
  • Assigns ownership directly to challenge 17’s generated history file instead of recursively changing the entire old_admin home directory.

- Align challenge titles across README, verify names, certificate and
  test script; README table is the source of truth.
- Add a module docstring to every setup/challenges/chNN_*.py.
- Rewrite all 18 hints as nudges that point at concepts, not the exact
  tool, field or flag. README Skills column is concept-only.
- ch11: write the broken nginx config directly instead of patching the
  default one with replace_once.
- ch16: five-link chain with a relative ../ hop and decoy links to a
  fake flag; README says to start at follow_me.
- ch17: three users' histories with decoy secrets; the flag is in a
  curl header, not an export line.
- ch18: test now reads the label without sudo, matching the learner path.
- AGENTS.md: document the title, docstring and hint standards.

Tested: basic run passes 28/28 on GCP and Azure. AWS and reboot not run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4703c39f-f11c-4c63-b095-09708ed6ff8f
@madebygps

Copy link
Copy Markdown
Collaborator Author

Pushed 53bd408 with a round of review changes.

Consistency

  • Challenge titles now match everywhere (README, verify names, both certificate lists, test script). The README table is the source of truth.
  • Every setup/challenges/chNN_*.py has a module docstring: title, learner goal, skills tested, what it plants. No solving commands.
  • README Skills column is concept-only for all 18 rows.
  • AGENTS.md documents these standards so future challenges follow them.

Hints

  • All 18 hints rewritten as nudges. They point at a concept or a man page, not the exact tool, field, path or flag.

Challenge changes

  • ch11: writes the full broken nginx config directly instead of patching the default one with replace_once.
  • ch16: five-link chain with a relative ../ hop, plus decoy links to a fake flag. README now says where to start.
  • ch17: three users have histories, each with decoy secrets. The flag moved from an export line to a curl header. README and hint updated.
  • ch18: hint no longer gives the location or names the label. The test now reads the label without sudo, which is the real learner path.

Testing

  • Basic run: 28 passed, 0 failed on GCP and Azure. Ch16, 17 and 18 solve on both. Cleanup confirmed.
  • Not run: AWS (credentials expired) and --with-reboot.

@madebygps

madebygps commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

Draft social post

We just shipped an update to our Linux CTF.

Want to get hands on with a Linux lab that will test your skills in under 9 minutes of setup? That's the longest deploy we've seen.

You SSH into a real cloud VM and work through 18 challenges using nothing but the command line. On average, the VM is ready in about:

  • AWS: 1.5 minutes
  • Azure: 2.5 minutes
  • GCP: 6.5 minutes

Want to test your skills on real sysadmin tasks?

  • Track down a hidden file or a secret buried in a log, the kind of job find and grep were made for
  • Fix a permissions problem with chmod and get into a locked-down service over ssh
  • Work out what a service is doing with systemctl and journalctl
  • Dig through nested archives with tar
  • Chase a DNS oddity and watch traffic on the wire

Free, runs on AWS, Azure or GCP, and you finish with a completion certificate.

Think you can find every flag?
https://github.com/learntocloud/linux-ctfs

#Linux #CTF #CloudComputing #LearnToCode #DevOps

Track deploy, ready (SSH + setup wait), tests and destroy time for each
provider and print a summary table after the run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4703c39f-f11c-4c63-b095-09708ed6ff8f
@madebygps
madebygps merged commit 58f9690 into main Sep 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant