← Back to FOC
Instructor-Led Content

> deploy_lab_

Build and deploy hands-on training labs from any topic. Students get a browser, a live terminal, and real targets. You get a scoreboard, auto-unlocking challenges, and a single-command deploy.

How It Works

Students walk in, open a browser, and get dropped into a live terminal. Their first instinct: scan the network. They find hosts, but everything's locked down — filtered ports, hidden challenges. They can see the scoreboard but can't touch it. Curiosity is lit.

The instructor walks through the presentation — slides are live on everyone's phone. As each section wraps, the next set of challenges auto-unlocks based on what the class has already solved. No awkward "okay now try this" transitions — the lab progresses itself.

First blood gets confetti on the scoreboard. Teams race through challenges with real targets and real tools. Everything runs from a single command. Tear it down in one command. Redeploy in five minutes. Zero install on student machines. Just a browser.

Platform Architecture

platform/ The engine — courses opt in, never forced terminal/ Shell-in-a-Box web terminal (student workstation) scoreboard/ Flask progress tracker + tiered hint system init/ Flag generation (randomized per session) seccomp/ Security profiles for container hardening scripts/ preflight.sh Resource check (memory, CPU, disk, Docker) start.sh IP randomization + docker compose up reset.sh Tear down + regenerate install.sh Bootstrap installer courses/ pivoting/ Example: 9-hop network traversal CTF compose.yml References ../../platform/ for shared infra targets/ Course-specific containers hints/ Tiered hint JSONs tools/ Static binaries Design.md Full walkthrough

Student Terminal

Shell-in-a-Box: each student gets their own isolated container with a web terminal. No SSH keys, no client install. One tab per student.

Scoreboard

Flask-based progress tracker. Flag submission, 3-tier hints (Nudge/Guide/Walkthrough), auto-unlock by progression. First blood confetti.

Target Network

Isolated Docker networks. Each target bridges two subnets, forcing lateral movement. Decoy services on every host.

Preflight Check

Validates Docker, Compose, ports, disk, memory. Calculates resource budget per student count. Constructive failure messages.

Deploy a Lab

Prerequisites

Quick Start

git clone https://github.com/mwilco03/FOC.git
cd FOC

# Run preflight
./platform/scripts/preflight.sh

# Deploy the pivoting lab
cd courses/pivoting
docker compose -f compose.yml up -d

# Access:
#   Student Terminal:  http://localhost:4200
#   Scoreboard:        http://localhost:8080

Tear Down

# From courses/pivoting/
docker compose -f compose.yml down -v

Full Reset (new flags, new IPs)

../../platform/scripts/reset.sh

Build Your Own Course

A course is a directory under courses/. It must be independently deployable with no dependency on sibling courses.

Course Directory Structure

courses/your-course/
  compose.yml          # References ../../platform/ for shared infra
  .env.template        # Environment variable template
  targets/             # Course-specific Docker containers
    service-a/
      Dockerfile
      entrypoint.sh
    service-b/
      Dockerfile
      entrypoint.sh
  hints/               # 3-tier hint files per challenge
    challenge-01.json   # { "nudge": "...", "guide": "...", "walkthrough": "..." }
  tools/               # Static binaries students may need
  slides/              # Instructor presentation content
  instructor/          # Solution guide (password-locked)
  README.md            # What this course covers, how to run it

The Skill: Topic In, Lab Out

Give the platform a topic — it derives the curriculum, generates challenges, builds slide content, and emits the Docker infrastructure. No pre-made PowerPoint required.

# Input:  a topic
Topic: "Network Reconnaissance with Nmap"

# Output: everything
courses/nmap-recon/
  compose.yml           # 13 target services + student terminals + scoreboard
  targets/              # Dockerfiles for each vulnerable service
  hints/                # 3-tier hints per challenge
  slides/               # Reveal.js slide deck (maps 1:1 to challenge categories)
  instructor/           # Solution guide + pace guide
  .env.template         # Flags, passwords, student count

The .pptx is an output, not an input. Slides and challenges are co-derived from the same topic outline, so they stay in sync automatically.

Terminal Modes

Mode Use Case Resource Cost Attack Surface
shellinabox Terminal-only labs (default) ~128MB/student Minimal
guacamole Labs needing GUI (Wireshark, browser, forensics desktop) ~576MB/student Slightly larger

Guacamole runs one guacd per student (not shared), matching Shell-in-a-Box's isolation model. Decision rule: does the lab need a GUI? If no, use Shell-in-a-Box.

# Set in .env or compose override
LAB_TERMINAL_MODE=shellinabox   # default
LAB_TERMINAL_MODE=guacamole     # opt-in when GUI needed

Security Hardening

Students have passwordless sudo inside containers. The container itself must be a well-sealed box. Defense in depth — each layer is independent.

ControlWhat It Prevents
Socket proxy (not raw socket mount)Host takeover via Docker API
cap_drop: ALL + explicit allowlistCapability-based escapes
Custom seccomp profileDangerous syscalls (unshare, mount, ptrace)
no-new-privileges: trueSUID/SGID privilege escalation
read_only: true + tmpfsPersistent malicious writes
pids_limitFork bombs
mem_limit + cpusResource exhaustion DoS
userns-remap on daemonHost impact if escape succeeds
internal: true on isolated netsLateral movement to host/internet
privileged: false everywhereFull host access

Student Terminal Hardening

# In compose.yml
student-terminal:
  cap_drop:
    - ALL
  cap_add:
    - NET_RAW           # nmap SYN scans, ping
    - NET_BIND_SERVICE  # tools needing ports <1024
    - SETUID
    - SETGID
    - DAC_OVERRIDE      # sudo mechanics
  security_opt:
    - no-new-privileges:true
    - seccomp:../../platform/seccomp/student-terminal.json
  read_only: true
  tmpfs:
    - /tmp:size=64m,noexec
    - /run:size=16m
    - /home:size=128m
  pids_limit: 200
  mem_limit: 512m
  cpus: "0.5"

Dedicated Lab User (Recommended)

Run the lab under a dedicated system account. Isolates .env (flags + passwords) from the instructor's home directory. If a student escapes, they land as ctflab, not the instructor.

# Linux
useradd --system --create-home --shell /bin/bash ctflab
usermod -aG docker ctflab
chown -R ctflab:ctflab /path/to/FOC
sudo -u ctflab ./platform/scripts/start.sh

Preflight Resource Calculator

Before any docker build, the preflight script calculates whether the host can handle the lab at the specified student count.

STUDENT_COUNT=10
LAB_TERMINAL_MODE=shellinabox

Fixed infrastructure:       ~1,672 MB
Per-student (x10):          ~1,280 MB
Estimated total:            ~2,952 MB
Recommended (30% headroom): ~3,837 MB

Three tiers of output:

# Example failure output:
Insufficient resources. Options:
  1. Reduce student count:  STUDENT_COUNT=6  (saves 512 MB)
  2. Switch terminal mode:  LAB_TERMINAL_MODE=shellinabox (saves 4,480 MB)
  3. Use lighter desktop:   DESKTOP=i3 (saves 3,840 MB)
  4. Reduce target hosts:   TARGET_COUNT=8 (saves 320 MB)

Available Labs

More labs are generated from topics using the skill system. Each lab lands as a new directory under courses/.