#!/usr/bin/env python3 """End-to-end: does the credential the panel SHOWS actually log in over SSH? The bug being regression-tested: the panel/terminal reported `ctfuser` for all 16 challenges, but 10 of them (the imported XVI/XVII images) only provision `root`, so every participant login was refused. A correct-looking JSON payload proves nothing -- this opens a real paramiko session per challenge with exactly the username/password/port the UI hands out. """ import json import sys import paramiko from pathlib import Path BASE = Path("/opt/gemastik18-final") sys.path.insert(0, str(BASE / "panel")) import teams # noqa: E402 TEAM = int(sys.argv[1]) if len(sys.argv) > 1 else 1 st = teams.team_state(TEAM) if not st: print(f"team{TEAM} has no state.json") sys.exit(1) users = teams.challenge_ssh_users() ok = bad = 0 failures = [] for name, _coff, _soff in teams.CHALLENGES: p = st.get("ports", {}).get(name) if not p: continue user = users.get(name, "ctfuser") pw = st.get("chall_passwords", {}).get(name) or "" port = p["ssh"] cli = paramiko.SSHClient() cli.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: cli.connect("127.0.0.1", port=port, username=user, password=pw, timeout=12, allow_agent=False, look_for_keys=False) _, out, _ = cli.exec_command("whoami; hostname", timeout=12) got = out.read().decode().strip().replace("\n", " | ") # The container must actually be the account we claim it is. actual = got.split(" | ")[0].strip() if got else "?" if actual == user: print(f" {name:<15} {user:<8} :{port} OK -> {got}") ok += 1 else: print(f" {name:<15} {user:<8} :{port} WHOAMI MISMATCH -> {got}") failures.append((name, user, actual)) bad += 1 except Exception as e: msg = type(e).__name__ print(f" {name:<15} {user:<8} :{port} LOGIN FAILED ({msg})") failures.append((name, user, msg)) bad += 1 finally: try: cli.close() except Exception: pass print(f"\nteam{TEAM}: {ok} logins OK, {bad} failed") if failures: print("failures:") for f in failures: print(" ", f) sys.exit(1 if bad else 0)