web
Challenges

/b/locked

Time to prove you're not just another... new user.
tldr; The site tracks “solved” CAPTCHAs by dropping a solvedCaptchas cookie containing per-solve tokens stored in SQLite. The protected page re-parses that cookie in a different format and then verifies all tokens concurrently using a SELECT … then pbkdf2 … then DELETE flow.
By solving one CAPTCHA to get a single token, forging the cookie as token,token,… (10×), and hitting /protected, all 10 verifications race and succeed before the row is deleted, the elapsed time is ~0s, and the flag is rendered. The EJS view (views/page.ejs) prints it (templated as <%= flag %>).

How to get there?
You must make /protected think you solved 10 CAPTCHAs within 10 seconds. That page:
Reads tokens from the
solvedCaptchascookie.Sorts the
solvedAttimestamps and checkslast - first ≤ 10s.
We bypass the “ten different solves” requirement by reusing the same token 10× and abusing a race so every concurrent verifier counts it before deletion.

The vulnerability?
Setter (on /api/solve) serializes as JSON array:

Reader (on /protected) expects a comma-separated list:

Because of this mismatch, an attacker can supply any comma-separated string (not JSON) and the server will accept it.
Steps:
Fetch one CAPTCHA:
GET /api/captcha→ receive images +captchaId.Solve it once (DO IT manually) 🤷♂️.
POST /api/solve { captchaId, solution }On success the server:Inserts
id=token, hash, salt, solvedAtintovalidHashes.Sets cookie
solvedCaptchasto["<token>"](JSON array).
Extract the token from the cookie (
["<token>"]→<token>).Forge the cookie in the format
/protectedexpects (comma list), repeating the same token 10×:


ExploitMe

Finally! The dating app specifically designed for people who think "getting a shell" is more exciting than getting a phone number.
tldr; Next.js app lets users edit their profile through /api/edit. The code validates input with yup but never calls .noUnknown() and later builds the SQL SET list from the keys of the validated object. That’s a classic mass-assignment bug: you can smuggle arbitrary columns (e.g. is_admin) into the update.
A second bug: /api/chat/[matchId]/report lets any logged-in user mark any chat as reported. The reader for /api/chat/[matchId] grants access if you’re (admin AND reported).
So: register → onboard → POST /api/edit with {"is_admin":1} → POST /api/chat/4/report → GET /api/chat/4 → read the messages and extract the flag.
Where is the flag? I first able to identified it in the seed file of this narnia db

And to expose it, we have to invoke this lil rat with some permission
How to get there?
Create an account → receive a JWT.
Finish onboarding so
/api/editis allowed.Mass-assign admin via
/api/editby includingis_admin: 1in the JSON body.Report the target match via
/api/chat/4/report(no membership check).Read
/api/chat/4as an admin of a reported match and grab the flag from the returned messages.
Who is responsible for this vulnerability?
Because unknown keys aren’t stripped/rejected, sending {"is_admin":1} ends up in validated, then in SET "is_admin" = ?. Thats why if you’re admin and the match is reported, you may read that chat even if you’re not part of it. (read the chat 4 where they have the flag). But make sure you finished the onboard process first 🤷😭.
Boxbin

🎵 You're on Boxbin, you're on Boxbin... 🎵 Welcome to Boxbin, the totally-not-suspicious platform for sharing your hatred against any kind of box!
Paste these in the console of the site. I'm so lazy at this point
SPAM

The Italian government's latest digital authentication masterpiece. Built by the lowest bidder with the highest confidence. What could go wrong?
TL;DR: Chain four bugs to run XSS in the admin bot and steal the flag. First, a missing await in password-reset makes any reset token “valid,” letting you reset the admin (user 0). With admin creds, abuse a broken authorization check to self-assign the System group.
That unlocks an internal /api/internal/sync endpoint where profile fields aren’t sanitized—inject a <script> payload. The “test” service renders that profile verbatim, so when the bot views it, your JS executes in the bot’s browser and exfiltrates its cookies (flag).
The challenge is to make the bot visit a page where your JavaScript runs and reads document.cookie to exfiltrate that flag.

This lets you reset the admin’s password without a valid token, effectively an auth bypass.
After takeover, you can: Promote yourself to System via IDP Actions (assignGroup). Use the System-only sync endpoint to write unsensitized profile fields. Some webhook shenanigans.

snakeCTF{42m_3ur0s_w3ll_sp3nt_0n_s3cur1ty_f369f85ee7ed56f6}
Last updated