Skip to contentExploitQuest

Lesson 2 of 3 in Broken Authentication · 2 min left in this chapter

Forge The Token

A real bank back office, a real login, and a session token you can rewrite by hand. You will forge a token that makes you the controller, set it, and open the vault an analyst was never meant to reach.

3 min read

Not yet reviewed

Rookmentor

The lab for this chapter is the Ledger's back office. You have an analyst's login. But you are not going to log in as the controller — you are going to *write yourself* a controller's token.

Wrenlearner

Write it myself? Without the signing key?

Rookmentor

Without any key. That is the point of alg: none. Watch what it costs you: three lines and a trailing dot.

The forgery

A token is base64url(header) + "." + base64url(payload) + "." + signature. For an alg:none token, the signature is empty — so the token ends in a dot with nothing after it. You need the two JSON parts:

header   {"alg":"none"}
payload  {"sub":1,"role":"controller"}
  1. Line 1The header declares that this token needs no signature. The verifier honours it and skips the check entirely.
  2. Line 2role: controller is the claim that matters — the app reads your role from the token, not from the database. sub: 1 names a real user so the account resolves; the role is the forgery.

Building and setting it

Base64url-encode each part, join them with dots, and add the trailing dot for the empty signature. In your browser's console on the lab tab, encoding is one function each:

const b = (o) => btoa(JSON.stringify(o)).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'')
const t = b({alg:'none'}) + '.' + b({sub:1,role:'controller'}) + '.'
document.cookie = 'eq_ledger=' + t + '; path=/'
  1. Line 1base64url is base64 with two characters swapped and the padding removed — that is the whole difference.
  2. Line 3Set the forged token as your session cookie, then reload. The app now believes you are the controller, because its verifier believed the header.

Now do it

Forge the token, set the cookie, and open the Vault — the controller-only page an analyst has no link to. Inside is a controller reference. That reference is your flag, and it is unique to you. Submit the one your session shows.

You set sub: 1, which is an ordinary analyst. Why does that account get controller powers, when its real role in the database is not controller?

What actually went wrong

Two mistakes stacked. The verifier accepted alg:none, so the signature — the only thing binding the token to the server — was optional. And the app trusted the role claim inside the token instead of re-reading it from the database. Either alone is dangerous; together they let an analyst write themselves a controller's session in three lines.