电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 589 人浏览分享

PortSwigger JWT 安全问题

[复制链接]
589 0
最近看到 PortSwigger 上新出了一个靶场,主题是 JWT 安全。

0x01 前言

JWT 全称 JSON Web Token,是一种标准化格式,用于在系统之间发送加密签名的 JSON 数据。
原始的 Token 只是一个 uuid,没有任何意义。
JWT 包含了部分业务信息,减少了 Token 验证等交互操作效率更高。JWT 作为现如今高度分布式网站的首
选Cookie 之一,今天我们来谈论一下 JWT 的安全性问题。

0x02 JWT 是什么

要针对网站的 Cookie 下手,首先我们要知道它是什么。
JWT 由三部分组成,分别为 Header ———— 头部;Payload ———— 负载,Signature ———— 签名
它们之间由三个 .分隔,由 Base64 加密而来。
Signature 可用的 JWT 也被称作为 JWS。

我们以下面这一个 JWT 作为例子进行说明

eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ
wb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm
8sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5
MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9Zd
xEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOa
B5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xe
LwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA

Header 部分

Header 部分就像是货车的标志,告诉了我们这辆车上面装了什么易爆品啊,还是易燃品。

在 JWT 中 Header 部分存储的是 Token 类型和加密算法,它长成这样

{
  "alg": "HS256",   // 也可以是 HS512, RS256 等等
  "typ": "JWT"
}

Payload 部分

Payload 这个词中文意思为负载,也就是我们大货车上面的货物。Payload 里面存具体的业务数据比如用户 id 等等。

Payload 部分长这样

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Signature 部分

Signature 部分意为签名,这批货送到了,需要对方签收一下,这就是签名,我个人也喜欢把它理
解成 Secret,它是经历这样一个算法所生成的。

alg 对应的加密算法(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  我们输入的 Secret
) secret base64 encoded

我们可以在 jwt.io中体验一下 Signature 的使用。

JWT 与 JWT,JWE

"JWT vs JWS vs JWE"

这个概念了解就好了,从原理上来说是非常相似的。

简单来说,现在网上大多数介绍JWT的文章实际介绍的都是 JWS(JSON Web Signature),也往往导致了人们对
于JWT的误解,但是 JWT 并不等于 JWS,JWS 只是 JWT 的一种实现,除了 JWS 外,JWE(JSON Web Encr
yption) 也是 JWT 的一种实现。

JWT 会造成的危害

JWT 的漏洞经常与提权类漏洞的危害放在一起说,所以提权类的漏洞能造成什么样的危害JWT
产生的安全问题也能产生危害。

0x03 JWT 基础安全问题

JWT 所产生的安全问题,是设计上与逻辑上不恰当的设计所造成的。
其中,如果服务器未对签名进行校验,则可以任意修改数据,若进行了校验,则无法修改需要
我们通过其他手段进行辅助攻击。

1. 未对签名进行验证

前文我们说到,JWT 需要开发者提供一个 Signature ———— 签名,如果我们不对签名进行验证
极有可能产生如下的越权情况。

假设选择存在一个 JWT 如下

{
        "username": "carlos",
        "isAdmin": false
}

如果没有对签名进行认证,我们可以修改isAdmin属性的值为true,即可造成简单的越权。

Lab: JWT authentication bypass via unverified signature

JWT 未对签名进行验证

靶场要求,利用 admin 的越权账户删除 carlos 账户。

我们去到 "My Accout" 界面下,登录进去,抓包,认识一下 JWT

QQ截图20220706105444.png

接着,在 Burpsuite 里面,我们查看这串 JWT。

9999.png

{
        "iss":"portswigger",
        "sub":"wiener",
        "exp":1656054440
}

在 Burpsuite 当中对其进行修改并发包。

9998.png

此时我们已经是 admin 的账户了,然后去完成我们的删除 user 的操作

9996.png

成功 ~!

2. 未对加密算法进行强验证

这一种情况,也就是未对 Header 部分的 "alg"进行验证

我们可以设置 alg 为 none,绕过验证,从而实现攻击。

Lab: JWT authentication bypass via flawed signature verification

未对加密算法进行强验证

靶场要求,利用 admin 的越权账户删除 carlos 账户。

登录,抓包,在 /my-accout 接口处,查看 JWT 的内容,修改接口为 /admin并发包现在是
401 Unauthorized 的状态码。

13119.png

如图所示修改 sub 属性为 administrator,修改 alg 为 none。这里还需要将我们的 Signature 删除掉因为Signature
是通过 alg 算法生成的,但要保留"分割点",让其成为 JWT 的形式。

220.png

199.png

此时我们已经是 admin 的账户了,然后去完成我们的删除 user 的操作。

198.png

3. 爆破 Secret 进行越权操作

这里用到一个叫做 hashcat的工具,kali 机一般是自带的,如果没有安装的话可以通过如下命令进行安装。

sudo apt-get update

sudo apt-get install hashcat

爆破需要字典,这里是我在本道靶场中使用的 字典

通过如下命令可以进行 JWT 的 Secret 的爆破

hashcat -a 0 -m 16500 你的jwt /path/to/jwt.secrets.list

获得 Secret 之后我们又能做什么呢?Secret 是用来生成 Signature 的一个未知的部分所以知道它了之后
便可以进行越权操作,我们通过这一道靶场感受一下。

Lab: JWT authentication bypass via weak signing key

爆破 Secret 进行越权

靶场要求,利用 admin 的越权账户删除 carlos 账户。

先抓包,获取到 jwt 之后,我们使用 hashcat 进行 Secret 的爆破。

196.png

这里获取到了 Secret 为 "secret1",接着我们去到 jwt.io 下伪造身份。

194.png

现在我们成功伪造了一个 admin 权限的用户,再进行越权操作。Success ~!

193.png

0x04 JWT 标头注入

这里的注入分为两种情况,当连接到数据库进行验证的时候,可能会存在 SQL 注入
若未连接至数据库时,我们可以进行越权设计。
在 JWT Header 当中会存在名为 "JWK" 的属性之一JWK 这一属性是可选的而非向
alg属性一样是必填的。

JWK 英文全称为 JSON Web Key,是一个JSON对象,表示一个加密的密钥。JWK 中的字段表示密钥的属性。
因为是对象,所以 JWK 当中有一些参数如下。
jku(JSON Web Key URL) - 提供一个 URL,服务器可以从中获取一组包含正确密钥的密钥。
kid(Key ID) - 提供一个 ID,服务器可以使用该 ID 在有多个密钥可供选择的情况下
根据密钥的格式,标识正确的密钥。

一个完整的 JWT Header 长成这样,其中便含有 jwk 这一属性。

{
        "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
        "typ": "JWT",
        "alg": "RS256",
        "jwk":
        {
                "kty": "RSA",
                 "e": "AQAB",
                "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"n":"yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
        }
}

JWT Header 的注入也分很多种,下面我们一一举例

1. 通过 jwk 注入 JWT,形成 JWS

理想情况下,服务器应当使用有限的公钥白名单来验证JWT签名。如果使用的公钥白名单中配置不恰当
例如允许 jwk 的任意公钥,则会导致安全问题。

我们以下面一道靶场尝试攻击方式。需要先安装 Burpsuite 的 JWT Editor Keys插件。

Lab: JWT authentication bypass via jwk header injection

通过 jwk 注入 JWT

靶场要求,利用 admin 的越权账户删除 carlos 账户。

同样,登录,抓包。我们将 /my-accout 接口的包单独拿出来,选中 JSON Web Token 的界面将sub
的值从  wiener" 切换为  administrator

191png.png

切换完之后,点击我们安装的 JWT Editor Keys插件中的 New RSA Key,生成 2048 长度的 JWK 私钥。

190.png

这样子一来,我们的私钥就成功创建了,因为服务器后台不比对 JWK 的私钥是否合规我们可
以直接绕过,并进行越权认证。

189.png

现在我们成功认证为 administrator权限,发送删除请求即可 ~

188.png

2. 通过 jku注入JWT,形成 JWS

jku 通常在 JWT 的 Header 部分,它长这样。

26.png

以这一泄露为例,该JWT 使用 RSASHA256 进行加密,而 RSA 的加密需要n与e。我给大家先画幅
流程图理一下攻击思路。

22.png

前三步是 Burpsuite 的插件 JWT Editor Keys 可以完成的,后续操作只需要我们将 jku指向JWK
文件即可进行越权操作。

下面这道靶场就是通过 kid 的值匹配进行攻击

Lab: JWT authentication bypass via jku header injection

通过 jku 注入 JWT

靶场要求,利用 admin 的越权账户删除 carlos 账户。

在明确了攻击方式之后,我们先利用 Burpsuite 的插件 JWT Editor Keys 生成公私钥对上一道题目生成的公私钥对也可以拿来使用。

进入到 Expolit Server 中,在 Body 部分复制我们的 JWK 公钥。

21.png

直接拿出来的公钥是没有 "keys" 表头的,我们需要加上此标头,类似这样

{
    "keys": [
{
    "kty": "RSA",
    "e": "AQAB",
    "kid": "691edd2a-f7bf-4e14-b5c4-c5ec79c3dffb",
    "n": "oCBNZNRji19rBXUxFRI9toMCRwzxSZ1ckkCvLnuKc8r_ZvRhIHNHo7Flr8_1efAyaIwx_YG7zJZG41hZcpnDE3BfZy
m09dAM8T65BVLTmFolqpPcZIoqO_CCIK8JU1T0oRgDaW-PCobwC0axi0-LAgb5YbODuTxmwre6bjOwCGftEL9FNgjS5
TR9yB0ZxLEJTGGtk7tq5q_voRT93vmSXmjZvUnFmMXSUEIHshfXjh12XUOLs0Mjgn0gfAWM7RFbkXvF-MLvj_p26gdV3
j4zHUhPbeFoepzxcBGfVQXajWjj7xfisVga1Okjqp3S53ouNMpY9OEy-UmFz-QGNxKCKw"
}
    ]
}

前半部分,我们在本地生成一个 JWK,并将其存放到自己的服务器上面,已经完成了接下来是修改 jku
使得 jku 指向 服务器。

10.png

再点下面的 "Sign",选中生成的 Sign Key,并且选择 Don't modify header模式,Sign 即可。

9.png

现在我们已经提权完毕,执行删除操作 ~

8.png

3. 通过 kid 注入 JWT,与目录遍历攻击相结合

JWS 规范没有针对 kid 进行严格设置,比如必须是 uuid 的格式或者是其他的,它只是开发人员选择的任意字符串。
那么我们可以通过将 kid 指向数据库中的特定条目,或者是指向文件名,作为验证密钥。
当 JWT 使用的是对称加密算法的时候,极有可能存在目录遍历的漏洞,我们能够强制服务器使用其文
件系统中的任意文件作为验证密钥。

当目录遍历与 kid 标头注入 JWT 结合在一起时,我们可以先尝试读取dev/null这一文件,dev/null这一文件默认为空
文件返回为 null,我们可以在 Symmetric Key 中,将 k 值修改为AA==也就是 null,进行攻击。

我们来看 Port 这里的靶场

Lab: JWT authentication bypass via kid header path traversal

通过 kid 注入 JWT,与目录遍历攻击相结合

靶场要求,利用 admin 的越权账户删除 carlos 账户。

这里我们先要生成一个 Symmetric Key,也就是对称密钥,并将 k 的值修改为AA==,如图。

7.png

接着,我们在抓到的包中修改 kid 值,尝试用目录遍历读取dev/null此文件。并将 sub 修改为 administrator

6.png

点击下面的 Sign,使用 OCT8 的密钥攻击。

5.png

成功越权,再进行删除操作即可 ~

4. 其他的 JWT 标头攻击

cty 标头,意义为 Content Type,有时用于为 JWT 负载中的内容声明媒体类型,一般情况下是省略的。
我们可以尝试修改 cty 标头为text/xml或者是application/x-java-serialized-object,这也可能导致 XXE 注入与反序列化漏洞。

x5c (X.509 Certificate Chain);有时用于传递用于对 JWT 进行数字签名的密钥的 X.509 公钥证书或证书
链此标头参数可用于注入自签名证书,类似于上面讨论的 jwk 标头注入攻击。由于 X.509 格式及其扩展的
复杂性,解析这些证书也会引入漏洞。

类似的 CVE 有 CVE-2017-2800和 CVE-2018-2633。

0x05 Web 手的 Crypto 式攻击 ———— 算法混淆漏洞

一些基础知识,对称与非对称加密
可以使用一系列不同的算法对 JWT 进行签名。其中一些,如HS256(HMAC + SHA-256)使用 对称 密钥 这意味
着服务器使用单个密钥对 Token 进行签名和验证。显然,这需要保密,就像密码一样。

4.png

其他算法,如RS256(RSA + SHA-256)使用 非对称 密钥对。这包括一个私钥服务器用于对令牌进行签
名和一个可用于验证签名的数学上相关的公钥。

3.png

顾名思义,私钥必须保密,但公钥通常是共享的,以便任何人都可以验证服务器颁发的令牌的签名。

算法混淆漏洞的产生原因

根本原因:JWT 库的原生安全问题。

尽管实际的验证过程因所使用的算法而异,但许多库都提供了一种与算法无关的单一方法来验证签名也就是说我不论
是对称加密方式 RS256,还是非对称加密方式 HS256,它们产生 token 的算法是与提供的加密算法无关的。

当时学的时候我也愣了一下,后面看懂了。
我们可以根据下面的伪代码加以理解

在 JWT 库中定义了verify()方法

function verify(token, secretOrPublicKey){
        algorithm = token.getAlgHeader();
        if(algorithm == "RS256")
        {
                // Use the provided key as an RSA public key
        }
                else if (algorithm == "HS256")
                {
                        // Use the provided key as an HMAC secret key
                }
}

当我们使用 RS256 这种非对称加密的时候,他们可能总是将一个固定的公钥传递给该方法。

publicKey = <public-key-of-server>;
token = request.getCookie("session");
verify(token, publicKey);

因为publicKey是一样的,所以会导致在使用对称加密的时候,造成publicKey的泄露容易造成一系列的安全问题。

执行算法混淆攻击

还是画个流程图,清楚一点

2.png

/jwks.json泄露的算法混淆攻击

以下面这道靶场感受一下算法混淆攻击

Lab: JWT authentication bypass via algorithm confusion

执行算法混淆攻击

靶场要求,利用 admin 的越权账户删除 carlos 账户。

先进行第一步,获取它的服务器公钥,访问/jwks.json接口,前文我们提到过这个接口是也可能存在信息泄
露的可能的。将这个 JWK 复制下来,作为我们第二部的 RSA Key。

1.png

接着,进行第二步,到 Burpsuite 的 JWT Editor Keys 去。生成新的 RSA Key,这里用之前泄露的 JWK。

000.png

然后把这串东西选中 "Copy Public Key as PEM",将其进行 base64 编码操作,保存一下得到的字符串
这里编码要注意,上下的一串-----END PUBLIC KEY-----不要删掉。
保存完后,在 JWT Editor Keys 处,生成新的对称加密 Key,用之前保存的 base64 编码去替换 k 的值。
修改 alg 为 HS256,修改 sub 为 administrator。再进行 Sign 操作,最后发包即可。

998.png

/jwks.json未泄露的算法混淆攻击
在这种情况下,基于我们登录之后产生一个JWT,在logout之后重新登录,会产生一个不同的JWT
我们可以将两个 JWT 相比对,得到公钥。
Lab: JWT authentication bypass via algorithm confusion with no exposed key
/jwks.json 未泄露的算法混淆攻击

靶场要求,利用 admin 的越权账户删除 carlos 账户。

按照我们之前说的方式,登录登出,再登录,获取两个 JWT,将其放到 Port 提供的 docker 工具里面运行。

运行的命令如下

docker run --rm -it portswigger/sig2n <token1> <token2>

996.png

此脚本会输出一系列 token 的存在情况值

993.png

这里我们尝试每一个 Tempered JWT,Port 这里给了提示说是 X.509 形式的,所以我们只需要
将 X.509 形式的 JWT 进行验证即可。
当 Response 回应200时,代表 token 是有效的,若为302则代表了重定向
下图是一个成功的案例。

991.png

将这一 JWT 的 Base64 编码拿过来,先放到记事本里面暂存。去到 Burpsuite 的 JWT Editor Keys点击
New Symmetric Key,将上面的 Base64 编码拿过来替换此对称密钥的 k 值。
生成对称密钥之后,进行和之前攻击一致的 Sign 操作

990.png

此时已经成功越权,执行删除操作即可。

0x06 JWT 安全问题的防护

使用最新的 JWT 库,虽然最新版本的稳定性有待商榷,但是安全性都是较高的。

对 jku 标头进行严格的白名单设置。

确保 kid 标头不容易受到通过 header 参数进行目录遍历或 SQL 注入的攻击。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.