Commit Graph
14 Commits
Author SHA1 Message Date
Cyrene ae50acfe40 fix(ssh): per-challenge SSH login + phew buffering/leak/timeout
Passwords failed on 10/16 challenges while state.json looked correct:
- only the 6 native GEMASTIK XVIII images provision 'ctfuser'; every imported
  XVI/XVII image does 'echo root:${PASSWORD} | chpasswd' and logs in as root.
  set_ssh_passwords() hardcoded ctfuser, so chpasswd set a password on an
  account nobody uses -> 'Permission denied' everywhere.
  Registry gains a per-challenge 'ssh_user'; chpasswd now targets the real
  login (and ctfuser/ctf when present) and reports failures loudly.
- phew checker: chall.py block-buffers stdout through the docker exec pipe
  (PYTHONUNBUFFERED now set) and leaks chall.py inside the container on
  timeout (26 orphans, container saturated) -> reaps the whole exec process
  group. Startup does a fresh Pailier keygen (~12 s) so crypto reads need
  _CRYPTO_TIMEOUT, not the 5 s prompt default.

Adds panel/verify_ssh_creds.py (proves the state->container binding from
inside via a real login), audit_ssh_users.sh, reset_runtime.sh.
2026-09-26 14:40:10 +08:00
MythEclipse ef385c3397 fix: get all imported challenges building and running
Root causes found by prebuilding every challenge image in parallel:
- fjb: ghcr.io base is not anonymously pullable here -> official httpd:2.4.
  pnpm 12 (via corepack on node:20) fails the install with
  ERR_PNPM_IGNORED_BUILDS unless build scripts are approved; neither
  onlyBuiltDependencies in pnpm-workspace.yaml nor --no-ignore-scripts
  suppresses it. The working sequence is:
    pnpm install --ignore-scripts && pnpm approve-builds --all && pnpm rebuild
- xl + kode-viewer: node:20-slim-bookworm is not a real tag -> node:20-bookworm-slim.
- burvesigner: python-dev no longer exists in bookworm -> dropped (python3-dev
  was already there and the source has no py2 syntax).
- burvesigner/hirnfick/s3: apt update and install were separate RUN layers;
  with the bundled apt-insecure.conf the second invocation re-resolved against
  the EOL bullseye-security mirror and 404'd every package. Merged into one
  'update && install' layer (fix_apt_layers.py, idempotent).
- consolidate_images.sh: teams used to build a private image per team
  (team1-x ... team4-x) because no shared image existed. Since the password is
  applied at runtime via chpasswd, one shared services-<name> build is enough;
  this reclaims ~1.5 GB, which matters on a 79 GB disk.
- reconcile_team_state(): a challenge enabled while a team was down left
  state.json without ports/flag/password, so the next compose render died with
  KeyError. Now both the API and the CLI tools reconcile first.
2026-09-25 21:03:29 +08:00
MythEclipse 6d1ede8c2b fix: bulk challenge enable path (compose YAML, base images, async toggle, tooling)
- fix_dup_volumes.py: 4 canonical templates had TWO volumes: keys inside one
  service (invalid YAML -> 'mapping key volumes already defined'), which broke
  every enable for anti-alchemy/burvesigner/gemas-notes/kode-viewer.
- fjb: ghcr.io base is not anonymously pullable on this host; swapped to the
  official httpd:2.4 (its httpd.conf only uses stock modules). Added
  onlyBuiltDependencies to package.json (pnpm >=10 blocks esbuild's postinstall).
- xl + kode-viewer: node:20-slim-bookworm is not a real tag; use
  node:20-bookworm-slim. gift-voucher: buster -> bookworm.
- prebuild_images.py: build each challenge's shared services-<name> image once
  in parallel (passes a placeholder PASSWORD build-arg, since several Dockerfiles
  run chpasswd and fail on an empty arg).
- set_enabled.py / sync_all_challenges.py: batch registry flip + runtime apply
  that survives panel restarts and reports per-team results.
- Challenge toggle is now async: PATCH returns a job id, the client polls
  /api/challenges/jobs/<id> so a multi-minute build no longer blocks the panel.
  Added _SYNC_LOCK to serialize concurrent compose rewrites.
2026-09-25 17:01:42 +08:00
MythEclipse c6fd9ec268 feat: challenge registry-driven platform + XVI/XVII imports + admin toggle + domain rename
- Rename repo/domain: attack-defense-platform / attackdefense.imrnes.team (all refs replaced)
- challenge_registry.json: single source of truth (28 challs across gemastik18/xvi/xvii)
- teams.py: registry-driven CHALLENGES, set_challenge_enabled, sync_challenge_runtime
  (apply enable/disable to live teams: build/up or stop/remove + receiver restart)
- compose_gen.py: render per-team compose from canonical per-challenge templates
  (image reuse, per-team ports 30xxx, flag mounts, passwords)
- gen_canonical_composes.py: canonical docker-compose.yml for all services
- import_new_challenges.py: import XVI/XVII services + EOL base image fixes
  (debian:buster→bookworm, node:14→20, python:3.7-slim→3.11)
- receiver: xvi package (10 checkers) + xvii package (12 generic checkers),
  Challenge base reads PASSWORD_<team_port> from env; gen_receiver_main.py
  generates per-team main.py from registry
- main.py: /api/challenges returns full registry; PATCH /api/challenges/<name>
  toggles enabled + applies to live teams
- index.html: 🏗️ Challenge Manager tab (toggle per challenge, grouped by set)
- SLA bonus now dynamic (all enabled challenges, not hardcoded 6)
2026-09-25 14:04:33 +08:00
MythEclipse c35b23a37f feat: SLA dashboard per team + points system (100/flag, +50 SLA bonus) + badges juara/runner-up/3rd + scoreboard API public+admin
Panel: /api/scoreboard + /api/public/scoreboard; teams.py: points.json ledger, probe_team_sla_fast, sla_status_all w/ background refresher; team.html: SLA & Skor tab; index.html: admin SLA tab; leaderboard shows points; Phew checker timeouts raised for slow Paillier keygen
2026-09-24 00:49:05 +08:00
root 3ef905b3bb feat: team activity feed (attacks in/out) + activity tab + auto-refresh + leaderboard tab on team portal 2026-09-23 22:56:07 +08:00
root 877f14ecf3 fix: editTeam endpoint + leaderboard live name resolution + domains in team set + apt-insecure.conf in all service dirs 2026-09-23 21:50:16 +08:00
root 24dbf0a662 draggable topology + attack visualizer + tools in containers
- topology nodes draggable (pointer events, SVG transform), layout hint shown
- attack visualizer: /api/attacks logs attacker->target events; red pulsing
  dashed arcs on recent attacks (60s hot), ⚔ counts ok/fail
- submit_flag now takes attacker_idx vs target_idx (A/D semantics); UI has
  target dropdown (enemy teams), leaderboard records target
- containers get vim+curl+wget+netcat+git+pip3 (Dockerfiles blogpost/cdn/
  phew/sheesh/warmup); warmup base ubuntu:20.04 EOL -> 24.04
- team portal: target dropdown refreshed after login (was empty pre-auth)
2026-09-23 18:05:44 +08:00
root 44dc1ac852 feat: target matrix + reset scores/environment buttons
- /api/targets (admin): matrix of all teams' domain:port targets
- /api/reset/scores: wipe leaderboard (admin, confirm dialog)
- /api/reset/environment: stop all teams, remove containers+receivers+
  team dirs+systemd units, wipe scores, drop domains (admin, confirm)
- portal targets now only domain+port (no ssh/labels)
- UI: tab Target Matrix, header buttons Reset Skor / Reset Environment
  with confirm() alerts 'apakah anda yakin ingin mereset...'
2026-09-23 17:14:42 +08:00
root 72382c43d0 fix: guide link IDOR, full team-api IDOR hardening, loading overlay
- guide link now server-side replaced to /team/<idx>/guide (no /team/0 403)
- _check_team_host() applied to ALL team endpoints (login, info, targets,
  status, guide, portal, ssh-ws): host must match team domain; panel/gemastik
  host only with admin session. Cross-domain session reuse -> 403.
- host check BEFORE auth on info/targets (no team-existence oracle)
- loading overlay (spinner + text) on start/stop all-team/set; JS util
  showLoading/hideLoading
2026-09-23 17:02:52 +08:00
root 43ed3df557 feat: team portal with own login, SSH web terminal, targets & guide
- Portal tim punya login sendiri (password = ssh_pass, session team_token)
- SSH Web GUI: /api/team/{idx}/ssh/ws (WebSocket+paramiko) → xterm.js terminal
  (fix: ssh_to_ws non-blocking poll, chall_passwords per-container auth)
- Root <slug>.gemastik.imrnes.team → portal tim (bukan login admin)
- Host validation: /team/{idx} & /team/{idx}/guide 403 kalau host != team domain
- /api/team/{idx}/targets: daftar service tim musuh (attack target)
- guide.html: panduan SSH/attack/defense untuk peserta
- fix esc() String(s) (bug: (s||'').replace is not a function saat port number)
- set_ssh_passwords retry loop (container boot race)
2026-09-23 16:37:58 +08:00
root 5e44a70049 feat: team-specific subdomains + portal tim
- create_team now takes label -> slug -> <slug>.gemastik.imrnes.team
- ensure_team_domains() writes Traefik dynamic config (gemastik-teams.yaml)
- team portal at /team/<idx> (public, shows chall ports, SSH, submit form)
- /api/team/<idx>/info + /api/team/<idx>/status (server-side receiver auth)
- UI: name inputs per team (set count -> labels), domain link in card
- delete team endpoint drops its domain
2026-09-23 16:18:11 +08:00
root 1ca963b2b7 feat: multi-team orchestrator - topology UI, team management, flag randomizer, public submit + leaderboard
- panel/teams.py: create/start/stop teams with isolated ports+creds, per-team receivers with CHALLENGE_PORT/CONTAINER env, flag randomization, submit validation + leaderboard
- panel/main.py: /api/teams, /api/teams/{idx}/randomize, /api/flag/submit, /api/leaderboard, /api/public/teams, /submit page
- panel/static/submit.html: public flag submission UI for teams
- receiver: _ch_port/_ch_container read .env per team, container name overrides
- .gitignore: exclude teams/, .venv, __pycache__
2026-09-23 15:14:52 +08:00
Hermes 6eb0dabb58 feat: add Gemastik A/D control panel (web UI for receiver)
- FastAPI app at panel/ proxying receiver API server-side (admin creds stay server-side)
- Login-protected dashboard: SLA status, rotate flag, restart/rollback/activate/deactivate, SSH creds, command history
- Runs as systemd service gemastik-panel.service on :18081
- Published at https://panel.gemastik.imrnes.team via Traefik
2026-09-23 14:26:26 +08:00