> For the complete documentation index, see [llms.txt](https://aenosh-rajora.gitbook.io/cyber-codex/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://aenosh-rajora.gitbook.io/cyber-codex/jwt-warfare-obfuscation-cracking-and-red-team-exploits.md).

# JWT Warfare: Obfuscation, Cracking, and Red Team Exploits

<figure><img src="https://cdn-images-1.medium.com/max/800/1*sa_IiIvszpYoJXF5xyl73w.png" alt=""><figcaption></figcaption></figure>

## 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:

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VybmFtZSI6ImFlbm9zaCIsInJvbGUiOiJhZG1pbiJ9.
wBwbm_z1gdu9OtUsAoOhPtUp9dJYWpA7U2oPeM4osbQj
```

**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 <a href="#bc43" id="bc43"></a>

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:**

<figure><img src="https://cdn-images-1.medium.com/max/800/1*nzZzZMISGMY4fyXRcP6-xw.png" alt=""><figcaption></figcaption></figure>

**Decode Example:**

```
echo '<base64>' | base64 -d  # Only works for header/payloads
```

Or use tools like JWT tool

{% embed url="<https://github.com/ticarpi/jwt_tool>" %}

```
python jwt_tool.py <token> -d 
```

In older versions

```
python3 jwt_tool.py <token> -d #python2 is used as default in older versions of linux and when using python in terminal, it automatically choose python2
```

## Cracking JWTs <a href="#c45e" id="c45e"></a>

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:

```
python jwt_tool.py <token> -C -S <wordlist>
```

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.**

```
python jwt_tool.py <token> -X -pk public.pem -A HS256
```

> `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:

```
{“alg”:”none”}
```

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

```
python jwt_tool.py <token> -S none
```

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:

```
python jwt_tool.py <token> -E -pc ‘cracked_secret’ -A HS256
```

## Challenges in Extracting or Exploiting JWTs <a href="#id-6d33" id="id-6d33"></a>

### **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

```
curl -b “auth=<jwt>” http://target.com/dashboard
```

### **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) <a href="#id-38f3" id="id-38f3"></a>

#### **TryHackMe: JWT Room**

{% embed url="<https://tryhackme.com/room/jwtsecurity>" %}

* Teaches `alg:none`, weak secret cracking
* Modify the payload to escalate privileges
* Bonus: Use BurpSuite’s JWT editor extension

#### **HTB: “JWT Secrets” Challenge**

{% embed url="<https://www.hackthebox.com/machines/secret>" %}

* 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 <a href="#id-2eb8" id="id-2eb8"></a>

<figure><img src="https://cdn-images-1.medium.com/max/800/1*kWeVoBxnDhm5LBjQ3rXhnQ.png" alt=""><figcaption></figcaption></figure>

Always **verify tokens server-side** with trusted libraries.

## Example Google CTF 2025 — Cracking the JS Safe 6.0 <a href="#id-1dd4" id="id-1dd4"></a>

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

<figure><img src="https://cdn-images-1.medium.com/max/800/1*G-6_uFgRK5ej8cc3PaNQhA.png" alt=""><figcaption></figcaption></figure>

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:

```
pool = rot47(“?o>`Wn0o0U0N?05o0ps}q0|mt`ne`us&400_pn0ss_mph_0`5”)
```

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 <a href="#b326" id="b326"></a>

```
# Decode JWT parts
jwt_tool.py <token> -d

# Crack secret
jwt_tool.py <token> -C -S rockyou.txt

# Try 'none' alg
jwt_tool.py <token> -S none

# Modify and re-sign
jwt_tool.py <token> -E -pc 'secret' -A HS256
```
