Files
2026-08-26 11:38:46 +03:00

1.9 KiB

Findings — Brunnerne 2026 A/D

arena-battle (pwn, port 1337->31337)

Status: partially patched (see services/arena-battle/PATCH_NOTES.md items 1-7). Sploit: challenges/pwn/arena-battle/work/sploit.py (+predictors.py) — token prediction via unsalted glibc rand(); verified 15/15 flags vs vulnerable build.

Remaining holes in OUR patched server (audit 2026-08-26)

  • [P1] NOTE_CREATE lines logged verbatim to logs/server.log -> any file-read anywhere on box = flag dump. Fix: redact.
  • [P2] SLA: ATTACK ignores current_turn; anyone can FIGHT+ATTACK our checker's fighter to hp=0 (dead forever until 1h cleanup) + steal gold. Fix: auto-revive dead fighters after ~60s.
  • [P3] Memory DoS: battles map never erased, b.logs unbounded, inventory push_back loop bounded only by gold. Fix: caps + GC of ended battles.
  • [P4] LOGOUT leaves fighter_battle entry (teardown skips because client_fighter already erased) -> ghost-battle desync. Fix: logout ends battle.
  • [P5] write() not looped -> partial-write truncation on big NOTE listings.
  • Cleanup thread erases fighter_battle[fid] for OLD inactive battle even if fid is now in a NEWER active battle (minor desync, low prio).

Offense roadmap (vs other teams' half-fixes)

  • default-seed rand(): DONE (glibc+darwin predictors).
  • srand(time(NULL)): TODO — brute-force seed from 1-2 self-registered tokens.
  • std::mt19937(time) / fixed seed: TODO — own mt19937 impl + state recovery from tokens we harvest by registering (REGISTER echoes TOKEN).
  • NOTE_GET has no rate limit across reconnects (MAX_BAD_TOKENS is per-conn).

Verified facts

  • work/server.cpp == services_vulnerable/arena-battle/server.cpp (diff clean).
  • Flag format [A-Z0-9]{31}= ; store = fighter notes; NOTE_GET auths on token alone.
  • checker_sim.py: REGISTER CheckerX warrior + NOTE_CREATE .

Other services (not started)

  • rusgram, tiktak, "services 4" — pending triage.