webfreemedium

SSOS

hackthebox

Task: HTB-style OAuth2 SSO web app (nginx + Express/passport client + Go/Gin provider) with a teacher Puppeteer bot that submits the flag at startup. Solution: win a registration race for the fixed student account, then use a text/plain JSON CSRF (Gin ShouldBindJSON ignores Content-Type) delivered via the bot's /submit-url to swap the shared cookie jar's SSO token to our session, so the bot submits the flag into our own account.

$ ls tags/ techniques/
startup_registration_racecookie_swap_csrftext_plain_json_csrfoauth_session_takeoverbot_url_visit_abuse

$ cat /etc/rate-limit

Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.

SSOS — Hack The Box

Description

Homework? Never heard of her. Let's dance.

A single-domain education platform protected by an OAuth2 SSO provider:

  • nginx (internal port 1337, mapped to a random external port per instance) routes by Host header.
    • edulearn.htb → Express client app (Node.js, EJS, passport-oauth2) on 127.0.0.1:3000.
    • sso.edulearn.htb → Go/Gin OAuth2 SSO provider on 127.0.0.1:3002.
    • Default server 302-redirects unknown hosts to edulearn.htb (preserving port).
  • A Puppeteer "teacher bot" (puppeteer-core, HeadlessChrome 130) runs inside the container, resolves both hosts to 127.0.0.1, and has no useful external egress.
  • All secrets (JWT_SECRET, CLIENT_SECRET, SESSION_SECRET, teacher/student passwords) are generated per-container with openssl rand — not guessable or forgeable.

Goal: read the real flag, which the bot submits into a student assignment once at container startup.

Analysis

Bot behavior (bot/index.js initialSetup(), runs ONCE at startup)

The bot drives a single Puppeteer browser whose pages all share one cookie jar. At startup it executes, in order:

  1. loginUser(teacher, teacherPw) — SSO login form (sets SSO token cookie = teacher).
  2. loginSSO(teacher) — OAuth authorize, sets the client session = teacher.
  3. createAssignment ×3 — as teacher.
  4. registerUser([email protected], STUDENT_PASSWORD) — random password.
  5. loginUser(student, STUDENT_PASSWORD) — SSO login form.
  6. loginSSO(student, STUDENT_PASSWORD)CRITICAL BUG: this function ignores its email/password parameters and authorizes using whatever token cookie is currently in the shared browser jar.
  7. submitFlagToAssignment() — types process.env.FLAG into the first assignment's submission textarea, submitting as the current client-session user.
  8. loginUser(teacher) + loginSSO(teacher) — restore teacher.

...

$ grep --similar

Similar writeups