the_open_door
coffee
ESEN
← Back to index

JWT Forgery (Embedded JWK, Weak RSA)

Full command arsenal in the cheatsheet

A JWT signed with RS256 is validated with an RSA key: the server signs with the private key and verifies with the public one. The abuse shows up when two design mistakes meet.

The first is trusting the key that travels inside the token itself. Some implementations carry the public key in a jwk field (in the header or the payload) and validate the signature against that embedded key instead of one stored on the server. If the attacker can swap that key, they can sign anything: the token self-validates.

The second, and the one that seals the deal, is a factorable RSA modulus. RSA's security rests on n = p·q being infeasible to factor when p and q are large. If the generator builds n with a tiny factor (say n = big_prime · q with q only ~20 bits), n factors instantly by trial division with small primes. Recover q, get p = n / q, then phi = (p-1)(q-1) and the private key d = e⁻¹ mod phi. With the rebuilt private key you re-sign the token flipping whatever claim matters (a role from customer to administrator).

import sympy, jwt, base64
# n and e come from the token's jwk field
factors = sympy.factorint(n)        # n has a small factor: falls at once
p, q = list(factors.keys())
d = pow(e, -1, (p-1)*(q-1))
key = RSA.construct((n, e, d, p, q))
payload['role'] = 'administrator'
print(jwt.encode(payload, key.export_key(), algorithm='RS256'))

The two conditions don't always coincide: sometimes the embedded key alone is enough (if the server accepts it blindly), sometimes the factorization alone (if the public key is known but weak). Here both lined up.

How to detect it. The signature is a JWT arriving with a key embedded in the header (jwk/jku/x5c), which a well-configured server should never accept: a gateway/WAF inspecting the token header can flag or reject any incoming jwk. Server-side, accepting a token signed with a key other than the trusted one, or a token whose role/privilege claim changes between requests of the same session, is the indicator. An n (modulus) with small factors in issued keys is the underlying weakness to audit.

Defence. Never validate against a key included in the token; use a fixed, trusted public key. Generate RSA keys with a serious library (2048-bit moduli with two large primes), never by hand.

Toolsjwt_tool

Machines where it's used