69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
#!/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)
|