Page cover

cookieJWT Warfare: Obfuscation, Cracking, and Red Team Exploits | Cyber Codex

What is JWT?

JWT (JSON Web Token) is a compact, URL-safe method of representing claims between two parties. It is used mostly in stateless authentication. JWTs are often passed via cookies, headers, or local storage.

A JWT has 3 base64-encoded parts:

<Header>.<Payload>.<Signature>

Example:

Structure:

  • Header: Specific Algorithm (e.g. HS256)

  • Payload: Contains claims like username, roles, etc.

  • Signature: Ensures integrity of header & payload

JWTs are commonly used in API authentication and session management. The server issues a token after login, and the client includes it in future requests.

JWT Obfuscation Tactics

While JWT is readable (via base64), attackers or even lazy devs sometimes obfuscate them for complexity or security through obsecurity.

Why Obfuscate?

  • Bypass security controls

  • Hide internal claims (e.g., role=admin)

  • Prevent easy inspection

Common Obfuscation Tactics:

Decode Example:

Or use tools like JWT tool

In older versions

Cracking JWTs

There are multiple ways to break JWTs depending on how they are implemented. Let’s dive into each.

Brute Forcing HMAC Secret (HS256)

If the JWT is signed with a weak secret:

You might find secrets like:

  • admin

  • password123

  • jwtsecret

Works only if the algorithm is symmetric (HS256) and the key is guessable.

Algorithm Confusion: RS256 to HS256

If a JWT is signed using RS256 (asymmetric), but the server doesn’t validate the algorithm properly, you can swap it to HS256 and sign with the Public Key.

public.pem file typically stores a public key in PEM (Privacy Enhanced Mail) format, commonly used for encryption and digital certificates with PKI.

CVE-2018–0114 made this famous.

The none Algorithm Attack

Earlier JWT libraries allowed tokens to have:

Then ignored the signature altogether. If the server accepts it:

Remove the signature, and replay. You’re now “logged in.”

Claim Forgery

Manually change the payload to “admin”: true and sign again with cracked secret:

Challenges in Extracting or Exploiting JWTs

When JWTs are Stored in Cookies

  • Harder to see in HTTP requests

  • BurpSuite is required to intercept and extract

  • Needs cookie jar awareness in scripts

When Stored in LocalStorage

  • Need XSS to steal from the browser

  • No access via server-side only enumeration

JWT Signature is Strong

  • RS256 with rotated keys

  • HMAC secrets not crackable

JWT is Short-Lived

  • Short expiry time = can’t replay easily

  • Need to intercept while valid

Real Labs (TryHackMe, HTB, Own Labs)

TryHackMe: JWT Room

  • Teaches alg:none, weak secret cracking

  • Modify the payload to escalate privileges

  • Bonus: Use BurpSuite’s JWT editor extension

HTB: “JWT Secrets” Challenge

  • Find the leaked key in JavaScript

  • Modify the token and hijack the admin session

Bonus: Create Your Own Lab

  • Use jsonwebtoken in Node.js

  • Set up weak secrets, test none bypass

Defense: How to Actually Secure JWTs

Always verify tokens server-side with trusted libraries.

Example Google CTF 2025 — Cracking the JS Safe 6.0

This isn’t a direct related to JWT Tokens, but it feels like a weaponized JWT obfuscation puzzle

This challenge is posed as a quirky localStorage-based “JS Safe”, a front for some next-level client-side obfuscation. The goal? Recover the flag hidden behind a password check that is leveraged heavily with instrumented JavaScript and anti-debugger traps.

Frontend Instructions:

// Open Dev Tools and type: // anti(debug); // Industry-leading antidebug! // unlock(“password”); // → alert(secret)

But this was bait.

Challenge Mechanics:

Prototype poisoning

A fake anti(debug) that breaks your DevTools

A check() function that

  • Validates the password via a deterministic PRNG (Pseudorandom number generator)

  • Uses a ROT47-decoded character pool

  • Evolves dynamically using Function.call

  • Streams characters using a shift() based comparator

Attack Strategy:

  • Ignore the bait. Disassemble the JavaScript logic.

  • Identify core PRNG logic:

j = ((i || 1) * 16807 + step) % 2147483647;

  • Recover the character pool with ROT47:

Simulate the keystream:

  • Pull characters

  • Compare using PRNG + shifted index

Filter final result to match CTF format:

  • CTF{[0-9a-zA-Z_@!?-]+}

Final Result:

unlock(“CTF{redacted}”);

Bonus Insight:

This wasn’t about brute-force or headers, this was a psychological puzzle, blending:

  • Cryptographic structure

  • Obfuscation

  • Dev tool misdirection

TL;DR Cheatsheet

Last updated

Was this helpful?