攻击JWT使用X509证书
在整理先前博客资料时,我注意到一个有趣的JSON Web签名(JWS)头部参数,并希望深入探究。RFC 7515第4.1节列出了已注册的头部参数,其中x5u和x5c头部引起了我的关注。这些头部利用X.509证书,并定义了存储公钥以验证JWS完整性的位置。
对于这两个头部,攻击者可以使用自己的私钥对令牌进行签名,并修改头部值以指定其公钥进行签名验证。此时,攻击者将完全有权修改令牌声明,而服务器会接受这些信息。虽然这不是新型攻击,但我未能找到可轻松利用此缺陷的Burp扩展。本文将逐步解析攻击原理,并演示我构建的用于利用这些头部的Burp Suite扩展。
1.1 设置
要开始此攻击,我们需要一个易受攻击的应用程序进行测试。我为此创建了一个基于Flask的易受攻击API。
https://github.com/Tsynack/JWT_X509_Re-Signer/tree/main/Example%20API
图1 - 运行示例API
为了使测试更简便,我还构建了一个自定义Burp扩展,允许修改头部和声明。该扩展还可用于重新签名令牌。扩展在此处获取:
https://github.com/Tsynack/JWT_X509_Re-Signer/tree/main/Burp%20Extension
注意: 扩展依赖Burp扩展设置中的Jython。
要安装扩展,导航至Extensions > Add > Extension Type: Python > 并选择JWT_x509_Re-Sign.py文件。
图2 - 加载JWT重新签名器
扩展加载后,Burp的HTTP历史或Repeater中包含JWS的任何请求都应有一个标记为“Re-sign JWT”的标签页。
图3 - 扩展已安装
执行此攻击所需的最后一项是用于签名令牌的X.509私钥及相关证书,以便服务器验证签名。使用OpenSSL,可以通过以下命令完成:
|
|
1.2 攻击剖析
快速回顾一下,JWS包含三个部分:
- 头部 - 包含有关签名生成方式的详细信息,并可能包含JWS内容的相关信息。
- 声明 - 包含有关认证过程的详细信息。一些示例声明包括:
- Iat(签发时间) - JWS生成时的纪元时间
- Exp(过期时间) - 服务器不再接受令牌的纪元时间
- Sub(主题) – 与令牌关联的用户
- 签名 - 声明与头部中列出的算法结合生成签名,确保令牌在服务器处理请求前未被篡改。
图4 - 示例令牌结构
图5 - 示例头部
图6 - 示例声明
在JWS的RFC中,概述了两个可选头部参数:
- x5c - 包含X.509公钥证书或证书链
- x5u - 指向X.509公钥证书或证书链的URI
公钥是服务器验证令牌签名并确定声明是否被篡改的方式。如果服务器使用这些参数的值来验证签名,则我们有机会修改声明并使用自己的密钥对令牌进行签名。
1.3 概念验证
使用前面提到的示例API,我们将向Burp的Repeater发送几个请求以篡改令牌。在示例API文件夹中,我包含了一个API_example_requests.txt文件,其中包含用于生成登录和验证请求的curl命令。您应能复制并粘贴登录命令,并在响应中接收令牌。令牌需要复制到验证命令中。
图7 - API登录
图8 - API验证请求
如果一切正常,Burp的代理历史中应记录这两个请求。右键单击/verify请求并将其发送到Repeater。
在Repeater中,导航至“Re-sign JWT”标签页。按下解码按钮将对令牌头部和声明进行base64解码。对这些值的任何修改将在令牌重新签名后反映。首先将sub声明修改为root。
图9 - 解码并修改声明
对于第一次攻击,我们将公钥证书直接嵌入x5c参数。为此,您需要导入之前使用OpenSSL生成的X.509私钥和证书。
图10 - 导入私钥和证书
由于我们将证书嵌入令牌,选择使用x5c头部重新签名令牌并点击“Attack!”请求中的令牌将自动更新为新签名的令牌。发送请求应返回200 OK,表明服务器已接受更新的令牌。
图11 - 重新签名的令牌被服务器接受
如果您已到达这一步,恭喜您通过使用自己的私钥签名令牌成功利用了该漏洞!
1.4 攻击x5u
x5u头部不是将证书内容直接嵌入令牌,而是将服务器指向可找到内容的URI。要利用此漏洞,我已将cert.pem托管在我的Web服务器上,并将在扩展的相应字段中添加URL。
确保将重新签名的方法更新为x5u头部,并点击“Attack!”发送请求时,托管证书的Web服务器应收到对cert.pem的请求,表明API在验证签名时已向外发出请求。
图12 - 访问日志显示外部交互
API响应应显示200 OK,表明签名和声明已被接受。
图13 - 利用x5u头部
1.5 结论
对于每个已识别的头部,问题在于服务器信任提供的证书以验证令牌签名。作为攻击者,我们可以控制头部的值,从而提供自己的证书。最终结果是一个被破坏的令牌,允许任何人更改声明中的值以冒充其他用户或执行权限提升。
作为开发者,请检查令牌的验证流程。即使您在签发令牌时未显式使用这些头部,服务器是否会接受头部值并根据提供的证书验证签名?实施代码以确保仅使用预期证书验证令牌签名。