$ cat writeup.md…
$ cat writeup.md…
tjctf
Task: Flask app with RS256 JWT authentication and role-based access to a vault drawer. Solution: Forge JWT by embedding attacker's RSA public key via jwk header parameter injection, then brute-force the required role (director) to access the flag.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
welcome to the basement; step inside and claim a badge.
English summary: A Flask web application that issues RS256 JWT tokens as "paper badges" to visitors. Users check in with a name and receive a JWT cookie (paper_badge) with role: "visitor". A protected /drawer endpoint (the "vault drawer") requires a specific elevated role to access. The goal is to forge a valid JWT with the correct role to open the drawer and retrieve the flag.
paper_badge cookie{"alg": "RS256", "kid": "front-desk-2026", "typ": "JWT"}{"iss": "paper-trail-office", "aud": "paper-trail-visitors", "sub": "...", "name": "...", "role": "visitor", "iat": ..., "nbf": ..., "exp": ...}/.well-known/jwks.json with kid front-desk-2026| Endpoint | Method | Description |
|---|---|---|
/ | GET | Main page with check-in form |
/check-in | POST | Issues JWT cookie with role: visitor |
/drawer | GET | Protected vault — requires elevated role |
/.well-known/jwks.json | GET | Public RSA key (JWKS format) |
/drawerThe 401 vs 403 distinction is critical: it tells us whether our forged token passed signature verification (403) or not (401).
...
$ grep --similar