BombThreat

websqlijwtauthentication

A fictional “detonation portal” where reaching the top clearance level is the whole objective — and three small, independently boring bugs chain into it without a single exploit that would survive a code review.

Spoiler-light notes — no flags, credentials or copy-paste exploits. Solve it yourself first.

Recon

The target is a small REST API behind a single web port. Three routes matter: a login, an MFA verification step, and the privileged action the whole box is built around.

That’s a deliberately narrow surface, and it tells you what the box is about before you send a single request. A login route, a second factor, and one action gated behind a “clearance” claim is an authentication and authorisation puzzle — not a hunt for a forgotten endpoint. When the surface is this small, the attack is almost always against the logic of the flow: who decides what you are, and how much of that decision the server actually re-checks.

The first useful find isn’t technical — it’s a comment left in the login page source, telling users that login errors with valid credentials are a known issue that “will be fixed within 365 days”. A note like that is an invitation to attack the authentication path specifically, and it’s the kind of thing that ships to production constantly.

Bug one — the injectable field is not the obvious one

The login takes a username and a password. The username is sanitised or uses a different query path; the password is interpolated straight into the query. Testing only the username would have produced a clean “not vulnerable” verdict on an endpoint that is trivially bypassable.

That’s the per-parameter lesson this box exists to teach: a negative result on one input is not a negative result for the endpoint. Fuzz every field, every parameter, every header — they frequently reach different queries.

A classic tautology in the password field authenticates you as an existing low-privilege user and returns a session plus a clearance level.

Bug two — the debug field that shouldn’t exist

The login response says MFA is required, and then — inside the same JSON — a _debug object carries the live one-time code in plaintext. Not a hash, not a masked value: the code you are supposed to receive by email, handed to anyone who asks.

Debug scaffolding is one of the highest-yield things to look for on any response. Grep every response you get for debug, trace, internal, test, otp, token — verbose fields leak the next step of the chain far more often than they leak anything else.

Feeding that code back to the verification route returns a signed session token carrying the low clearance level.

Bug three — the token that verifies itself

The privileged endpoint accepts a bearer token and checks the signature — but it lets the token choose its own algorithm. Switching the header to the “no signature” algorithm means the verification step is skipped entirely, and the payload is whatever you say it is.

So: take the structure of the valid token you were legitimately issued, rewrite the clearance claim to the highest level, and set the algorithm to none. No secret was recovered, guessed or needed.

This is the same failure as “the client decides how it will be authenticated” in any other form, and it appears in real applications often enough that it’s worth testing on every token-based endpoint you meet: flip the algorithm, strip the signature, watch whether the server cares.

It’s worth being precise about why it works, because the mechanism is what generalises. A signed token is three dot-separated parts: a header declaring how it’s signed, a payload of claims, and a signature over the first two. Verification normally means “recompute the signature using the algorithm in the header and compare”. If the header may name the no-signature algorithm, there is nothing to compute and nothing to compare — the server accepts a token whose third segment is empty. The defender’s own verification code is doing exactly what it was told; the flaw is that the attacker was allowed to give the instruction.

The other half of the lesson is where the claim lived. “Clearance level” was an ordinary field inside the payload, trusted after verification. Anything the client can put in a token and the server reads back as fact is, by definition, client-controlled — unless it is checked against a store the client cannot write to.

Takeaways

  • Test every input independently. The injectable parameter is often not the one named after the thing you’re attacking.
  • Debug fields in production responses are a direct roadmap — search for them deliberately.
  • Never let the token select its own verification algorithm; pin it server-side and reject everything else.
  • A chain of three “minor” issues is still a full compromise. Severity is a property of the chain, not of the individual bug.
  • Source comments and error messages are documentation written by the defender — read them as hints.