本文由公众号:rainy的安全小屋 投稿,大家可以多多关注下面的公众号,不定期发一些SRC案例
免责声明
道一安全(本公众号)的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他!!!
JWT基础
JWT格式
jwt格式:
base64UrlEncode(header) + “.” + base64UrlEncode(payload) + “.” + base64UrlEncode(signature)
1、header.payload.signature即头部.载荷.签名
2、举例:
如图右侧已解码数据即为jwt值base64解码后的数据
alg代表签名算法 ,对称算法有hs256 hs512等,非对称算法有rs256 rs512等。
tye代表jwt类型
载荷即为开发自定义字段,一般存在鉴权字段,如sub id username等。
签名即将base64编码后的头部与载荷用点连接后,与密钥一起作为输入,使用签名算法生成消息摘要,该摘要不可逆,用于防篡改。
HS256
1、HS256:使用SHA256哈希算法的 HMAC算法,是一种使用共享密钥的对称密钥哈希算法
2、SHA256:一种哈希算法,用于生成固定长度的消息摘要,不可逆。
3、生成签名:将头部与载荷分别base64url编码后点连接,和密钥一起作为输入,使用HMACSHA256算法进行签名,无需关注HMACSHA256算法具体流程。
签名 = HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
4、验证签名:base64解码头部与载荷 重新生成签名与接收的签名进行比对,相同则校验通过
RSA256
概述:使用SHA256哈希算法的RSA签名,是一种公私钥对的非对称算法,公私钥是配对的,私钥加密的数据只有其配对的公钥才能解密。
生成签名:将头部与载荷分别base64url编码后点连接,使用sha256生成原始消息摘要,将它使用rsa256的私钥进行加密,即通过rsa私钥加密的sha256哈希的加密消息摘要。
签名 = RSA256(
SHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload)
), 私钥
)
验证签名:base64url解码签名—>rsa公钥解密获取原始消息摘要,即RSA(public_key,Base64UrlDecode(signature))。生成原始消息摘要将其对比,相同则验证通过。
常见测试工具
https://github.com/ticarpi/jwt_tool
https://github.com/brendan-rius/c-jwt-cracker
https://github.com/hashcat/hashcat
burp插件jwt_editor
常见测试方法
未验证签名
开发只使用decode方法进行解码,verify方法才是验证签名。此时任意更改jwt用户id即可。
算法可为none
alg用来声明算法,若为none(4种大小写变形都尝试)时不进行签名
python3 jwt_tool.py jwt -X a
暴力破解密钥
1、jwt密钥字典
https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list
2、爆破方法
https://github.com/ticarpi/jwt_tool python3 jwt_tool.py jwt -C -d jwtsecret.txt
hashcat -a 0 -m 16500 jwt jwtsecret.txt
–show //查看结果
kid为/dev/null
kid用户标识密钥条目,如果指向/dev/null的话,则密钥为空。
使用burp插件jwt_editor,生成对称密钥后修改k值为空的base64编码(AA== ),修改kid和用户信息后重新签名
JWK参数注入
jwk是jwt头部的一个参数,是嵌入式公钥,服务器应该只信任白名单公钥,如果信任了用户注入的jwk公钥,只需用户使用其公钥配对的私钥进行加密,则导致通过验签。
使用jwt_editor插件生成rsa公钥
修改鉴权的用户信息后注入公钥
jku参数注入
jku(jwk set url)即放到某个url服务器上的jwk,验证签名时,后端会从jku指定的 url 获取jwk密钥。
使用jwt_editor生成rsa公钥 将公钥放到vps上并开启文件服务 (python3 -m http.server 8080),注意放置格式要为如下格式。
{
"keys":[
{
"kty": "RSA",
"e": "AQAB",
"kid": "5d7ec07c-47d0-4076-be08-481668d70129",
"n": "sABCsi3MN6wTIJZrNZ2qM6k7j2ZroZ-s84KvdNshK6-WaEaeCBRDmFOWl5-KLW0m0UfNaZT-yxl2UZUXELk3QIuT3j2dqBYeCZwGssFud3iFL6SYTpsq3rvSGn6tzst5G_ykkfFb_gItWul7pHdpRjhyHIJbeP6oY_hcuoXCNlwT__ykJfX-EYwxFb7IgrMFRZHhSPX2wZ466Fk0ZDW3wqnkBq-vvntD0yU4U5g1iqSKMFc6oKQr4iZ8wK5AwMwqGM3LE2vO-US7I1aeQfll-dOoJ51D_HIIYnRrJksebU7LXaJTeRHnx_cJ5Tyt4Pm8gYxzhOOXZgFWZiaWfUWzjw"
}
]
}
增加jku地址为文件服务地址,修改签名用户信息,重新签名。
特殊的jjwt
参考文章:
https://mp.weixin.qq.com/s/hscF3h-ae9Qt6B81etdCfg
原理
jjwt(https://github.com/jwtk/jjwt)是一个开源的jwt库,由于其说明文档不够详细,导致网上出现了很多错误的使用教程。
正确的使用–将密钥base64编码后传入
错误的使用–直接将密钥字符串传入
jjwt时生成自定义密钥的过程:
1、传入jwtsecert
2、base64解码jwtSecret,Keys.hmacShaKeyFor方法根据输入的字节码创建一个 HmacSHA 格式的密钥对象。
3、从上面的代码来看,如果我们没有传入base64编码值,而是普通字符串时会出现两个问题。传入的密钥存在特殊字符比如@,按道理来讲是无法被base64解码的(因为base64的码表里面只有两个特殊字符+和/) base64编码值是4的倍数,解码时也得是4的倍数,如果我们传入12345,按道理是无法解码的。
4、而jjwt在面对上述两种情况时均可以正常解码,原因是它有自己的base64解码逻辑,对传入的字符串做了如下处理:剔除特殊字符 不足4位数的倍数,删除至4的倍数
5、也就是说假如正确的密钥是1234,我们爆破字典中12345 1234a 1234@ 等等,只需前四位是1234,后三位无论是什么,最后经过jjwt的解码处理,最后都会变成正确的密钥。
将错就错的测试方法
如果开发使用jjwt 库时传入的是普通字符串,与正常的jwt爆破工具相比,我们就需要多一个密钥的base64解码过程。
将错就错的测试工具
公众号回复 jjwt爆破工具
也可以关注下面的公众号回复 jjwt爆破工具 获取工具
最后的倔强
如果常见测试方法均为奏效,由于是离线爆破,我们可以借助vps或在线平台爆破它个三天三夜
vps爆破:选用号称爆破密码最快的hashcat(hashcat -a 0 -m 16500 jwt jwtsecret.txt )
在线爆破平台:https://jwt-cracker.online/
原文始发于微信公众号(道一安全):SRC挖掘案例之JWT学习
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论