BaseCamp
alfactf
Task: a Go web app exposed a demo-to-VIP access flow guarded by one-time JWTs and a local revocation microservice. Solution: overload revocation checks until they time out, then reuse a supposed one-time VIP token to list course 4 and open lesson 16.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
BaseCamp — alfactf
Description
The challenge provided a web service at
https://basecamp-srv-ude4r2la.alfactf.ru/and a source archive for local analysis.
The target was a Go application with JWT-based auth and a separate local revocation service. The goal was to reach the hidden VIP lesson in course 4 and extract the real flag.
Analysis
Source review showed the important flow:
POST /api/auth/registerandPOST /api/auth/logincreate a normal user session.POST /api/courses/4/lessons/15/request-accessissues a short-lived JWT with rolevip,one_time=true, and a slug for demo lesson 15.GET /api/courses/4returns lesson metadata. When the JWT role isvip, it also returns slugs for demo and VIP lessons.GET /api/courses/4/lessons/access/{slug}serves VIP lesson content if the slug matches the JWTjti.
Course 4 contained:
- lesson 13: free
- lesson 14: free
- lesson 15: demo
- lesson 16: vip
The first promising idea was to forge a VIP JWT from secrets found in docker-compose.yml, including a sample JWT_SECRET. That did not work remotely: forged tokens were rejected with 401 invalid token, so this path was a false lead and not the real solve.
The actual bug was in revocation handling.
The auth middleware parsed the JWT, called revocation.Check(jti), and only rejected the request if the service replied successfully with revoked=true. If Check returned an error, the middleware only logged it and continued processing. After the handler completed, any one_time token was revoked via revocation.Revoke(jti).
The revocation backend stored revoked JTIs in a plain text file. Each check scanned that file line by line, while the service wrapped the operation with a very short timeout. Once the file grew and contention increased, revocation requests started timing out. Those timeouts became ordinary errors, and the main middleware failed open by accepting the token anyway.
...
$ grep --similar
Similar writeups
- [web][Pro]Code Control— undutmaning
- [web][free]Six-Seven— alfactf
- [web][free]SSOS— hackthebox
- [misc][free]Chrono Mind— HackTheBox
- [web][free]Никто, конечно, не чиллил— alfactf