JWT介绍空加密暴破密钥私钥泄露密钥混淆黑盒

2024-02-19 18:50

本文主要是介绍JWT介绍空加密暴破密钥私钥泄露密钥混淆黑盒,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

0x00 前言

0x01 JWT 介绍

1、什么是 JWT

2、两种身份验证方式的比较

3、JWT 的组成三个部分

4、JWT 的流量特征识别

0x02 JWT 漏洞利用

1、空加密算法(Header 中加密算法为 None)

2、暴力破解密钥

3、源码泄露私钥(JWT中私钥用于签名,公钥用于验证)

4、密钥混淆攻击(RS256 => HS256)

0x03 JWT 黑盒测试思路


0x00 前言

希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢! 

个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog

0x01 JWT 介绍

1、什么是 JWT

JWT(JSON Web Token):JWT 是一个遵循 JSON 格式的 Token,主要用于身份验证和访问控制,它由 Header、Claims、Signature 三个部分组成

2、两种身份验证方式的比较

与传统的 Cookie+Session 验证方式不同,基于 Token 的认证方式对于服务器无需保存任何用户信息(用户信息在 JWT 里),只需要保存特定加密算法的密钥来验证 Token 即可验证用户身份,服务器负担更小

  • 1、基于 Cookie+Session 验证流程

用户账号密码验证通过后,服务器将用户信息存储到 Session 里(Session 存放在服务端),并返回用户唯一的 session_id 写入到客户端 Cookie 里(Cookie 存放在客户端)。

用户下次请求会带上 Cookie 中的 session_id,然后服务器以此验证用户身份。

  • 2、基于 Token 验证流程

用户账号密码验证通过后,服务器会签发一个 Token(比如 JWT)给客户端,客户端收到后会将 Token 存放在 Cookie 或其他字段里。

用户下次请求会带上 Token,然后服务器使用密钥解密并验证用户身份。

以下为 JWT 认证的流程图:

3、JWT 的组成三个部分

以下为 JWT 的组成示意图,由头部、声明、签名三个部分组成。

  • Header(头部):用于声明加密算法(alg字段)、JWT类型(typ字段)等
  • Claims(声明):用于存储用户信息,如JWT面向的用户(sub字段)、JWT过期时间(exp字段)等
  • Signature(签名):用于对 Header 和 Claims 进行 Base64 编码和算法加密,拥有该部分的 JWT 被称为 JWS,也就是签了名的 JWT

以下为 JWT 解密后的示意图,需要补充的是加密算法 HS 表示对称加密,SA 表示非对称加密。

  • HS 的签名和验证都使用同一个密钥
  • SA 的签名使用私钥,验证使用公钥

4、JWT 的流量特征识别

对于人工识别而言,JWT 一般存在于 Authorization、Cookie 或者请求体里面,由 . 号分割为三个部分,并且 Header、Claims 都是以 eyJ 开头的 Base64 编码。

在工具的角度,可以使用 BurpSuite 插件配合 JWT 在线解析来识别。

BurpSuite 插件:Hae、JSON Web Tokens

JWT 在线解析:JSON Web Tokens - jwt.io

Hae 正常导入 jar 包后替换一下 config.yml 文件,JSON Web Tokens 直接到 Burp 商店下载就行,整体效果就是能通过颜色清晰的看到相关的流量包。

0x02 JWT 漏洞利用

利用工具(jwt_tool):https://github.com/ticarpi/jwt_tool

1、空加密算法(Header 中加密算法为 None)

JWT 支持将加密算法 "alg" 字段设定为 "None",此时签名会被置空,任何 JWT 都是有效的。

以 CTFShow - Web345 为例,观察到返回包中指示访问 /admin 以获取 Flag。

访问 /admin 后观察返回包,并未发现 Flag,考虑是 JWT 的问题。

解密数据包中的 JWT 值,发现用户是 user 而不是 admin,尝试修改为 admin,但是发现无法在线修改。

将 JWT 值发到 Burp 的 Decoder 模块,先进行 Base64 解码,将 user 替换为 admin 后,再 Base64 编码得到 admin 用户的 JWT 值。

重新访问 /admin,带上 admin 用户的 JWT 值,得到 Flag。

以 CTFShow - Web346 为例,同样观察到返回包中指示访问 /admin,解密访问 /admin 的 JWT 值,观察到加密算法为 HS256,面向用户为 user。

因为这里的 JWT 使用了 HS256 加密,也就是签名有效且会对 Header 和 Claims 进行编码和加密处理,所以当不清楚密钥的情况下,直接修改 user 为 admin 是不行的。

这里考虑两种思路:1、爆破密钥,显然难度较大;2、尝试将加密算法置空,也就是 alg=none

同样,将 JWT 值发到 Decoder 模块,先 Base64 解码,将 HS256 替换为 none,user 替换为 admin 后,再 Base64 编码。

但需要注意的是,使用此方法要先将 Signature 部分删除掉,因为加密算法为 none 必须将签名置空,并且需要将 Header 和 Claims 分别处理后再用 . 号连接,因为实测直接一起处理是不行的。

最终的格式为:Header.Claims.(注意最后面还有一个 . 号)

重新访问 /admin,带上 admin 用户的 JWT 值,得到 Flag。

上述方法略为复杂,更方便的当然是使用工具,比如 jwt_tool、Burp 插件 JSON Web Tokens 等。

使用插件 JSON Web Tokens,将 HS256 替换为 none,user 替换为 admin,并删除 Signature 部分,重新发包即可。

jwt_tool 常用命令如下:

# 使用None算法
python3 jwt_tool.py JWT_HERE -X a
# 自定义修改生成
python3 jwt_tool.py JWT_HERE -T
# 使用字典破解
python3 jwt_tool.py JWT_HERE -C -d dictionary.txt
# 指定密码测试
python3 jwt_tool.py JWT_HERE -C -p password_here

需要注意的是,jwt_tool 最好是在 Linux 上运行,我使用的 Kali 运行,并且需要先导入几个包,命令如下:

python3 -m pip install termcolor cprint pycryptodomex requests

然后启动 jwt_tool,使用 -T 自定义修改模式,根据提示将 HS256 替换为 none,user 替换为 admin,最后会自动生成对应 JWT 值。

复制生成 JWT 值并删除 Signature 部分,重新发包即可获取 Flag。

2、暴力破解密钥

以 CTFShow - Web347 为例,同样访问 /admin 得到的是 user 的 JWT 值,尝试空加密算法无果。

由于加密算法为 HS256 对称加密,比较容易爆破密钥,所以考虑使用 jwt_tool 爆破密钥,最终得知密钥为 123456。

python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.Vjqa5vYv9uRUqiaQpsDxlswGfK5n2umAp-NrY0p39bg -C -d key_dictionary.txt

在 jwt.io 输入密钥,修改 user 为 admin,重新生成 admin 用户的 JWT 值,发包即可获得 Flag。

3、源码泄露私钥(JWT中私钥用于签名,公钥用于验证)

以 CTFShow - Web349 为例,这一关给了一个 JS 文件,模拟的是源码泄露,具体代码如下:

代码解释1、当GET请求发送到根路径(‘/’)时,会执行以下操作:使用res.type()方法将响应的内容类型设置为html使用fs.readFileSync()方法读取当前工作目录下的public/private.key文件,并将其内容赋值给privateKey变量使用jsonwebtoken库的sign()方法生成一个JSON Web Token(JWT),其中包含用户信息为’user’,使用privateKey进行签名,使用RS256算法使用res.cookie()方法将生成的JWT写入名为’auth’的cookie使用res.end()方法发送响应内容为’where is flag?'的响应2、当POST请求发送到根路径(‘/’)时,会执行以下操作:设置响应内容类型为html获取名为’auth’的cookie的值赋值给auth变量使用fs.readFileSync()方法读取当前工作目录下的public/public.key文件,并将其内容赋值给cert变量使用jsonwebtoken库的verify()方法验证auth变量中的JWT是否有效,使用cert公钥进行验证。如果JWT中的用户信息为’admin’,则发送包含flag的响应;否则,发送包含’you are not admin’的响应

通过解密 JWT 得知其使用的加密算法为 RS256,和前面的不同是这里是非对称加密。

在使用非对称加密算法的 JWT 中,私钥用于签名,公钥用于验证。这是因为公钥是公开的,如果用公钥进行签名,那么攻击者便很容易伪造 JWT 了,显然不合理。

于是我们只要拿到用于签名的私钥,便可伪造 admin 用户的 JWT 拿到 Flag。这里通过泄露的 JS 代码得知私钥存放位置为当前目录下,于是直接访问下载 private.key。

拿到了私钥之后,利用其重新生成 admin 用户的 JWT 值。

这里我使用 Python 来生成,具体代码如下(需要注意这段代码需要导入两个包,JWT 和 PyJWT)

pip install JWT PyJWT

生成的 JWT 如下,将其以 POST 方式重新发送(泄露的 JS 代码得知的逻辑),得到 Flag 值。

总结:由泄露的 JS 代码得知验证逻辑,并得到私钥(用于签名)存放位置,利用私钥重新生成了 admin 用户的 JWT 拿到了 Flag,整个过程就像是一次身份的伪造。

疑问:为什么爆破使用对称加密算法(如HS256)的 JWT 的密钥容易,但爆破非对称加密(如RS256)却很难?

4、密钥混淆攻击(RS256 => HS256)

以 CTFShow - Web349 为例,这一关给了一整个源码包,其实模拟的也是源码泄露。

查看该源码包,发现里面有公钥 public.key 却没有私钥 private.key,于是无法像之前一样利用私钥重新生成 admin 用户的 JWT。

观察处理逻辑,签名使用的是 private.key,验证使用的是 public.key,我们已经得到了 public.key,那么要是签名也使用 public.key 不就万事大吉了吗?

于是考虑将加密算法替换为 HS256,这样签名和验证都使用同一个密钥 public.key,利用其生成 admin 用户的 JWT 即可获取 Flag。

这里我使用 Node.js 生成,代码如下,将得到的 JWT 值以 POST 方式重新发送,得到 Flag 值。

0x03 JWT 黑盒测试思路

首先找到需要 JWT 鉴权后才能访问的页面,如个人资料页面,将该请求包重放测试:

  • 1)未授权访问:删除 Token 后仍然可以正常响应对应页面
    2)敏感信息泄露:通过 JWt.io 解密出 Claims 后查看其中是否包含敏感信息,如弱加密的密码等
    3)破解密钥 + 越权访问:通过 JWT.io 解密出 Claims 部分内容,通过空加密算法或密钥爆破等方式实现重新签发 Token 并修改 Claims 部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
    4)检查 Token 时效性:解密查看 Claims 中是否有 exp 字段键值对(Token 过期时间),等待过期时间后再次使用该 Token 发送请求,若正常响应则存在 Token 不过期
    5)通过页面回显进行探测:如修改 Claims 中键值对后页面报错信息是否存在注入,Claims 中 kid 字段的目录遍历问题与 sql 注入问题

这篇关于JWT介绍空加密暴破密钥私钥泄露密钥混淆黑盒的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725609

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

Mysql BLOB类型介绍

BLOB类型的字段用于存储二进制数据 在MySQL中,BLOB类型,包括:TinyBlob、Blob、MediumBlob、LongBlob,这几个类型之间的唯一区别是在存储的大小不同。 TinyBlob 最大 255 Blob 最大 65K MediumBlob 最大 16M LongBlob 最大 4G

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

nginx介绍及常用功能

什么是nginx nginx跟Apache一样,是一个web服务器(网站服务器),通过HTTP协议提供各种网络服务。 Apache:重量级的,不支持高并发的服务器。在Apache上运行数以万计的并发访问,会导致服务器消耗大量内存。操作系统对其进行进程或线程间的切换也消耗了大量的CPU资源,导致HTTP请求的平均响应速度降低。这些都决定了Apache不可能成为高性能WEB服务器  nginx:

多路转接之select(fd_set介绍,参数详细介绍),实现非阻塞式网络通信

目录 多路转接之select 引入 介绍 fd_set 函数原型 nfds readfds / writefds / exceptfds readfds  总结  fd_set操作接口  timeout timevalue 结构体 传入值 返回值 代码 注意点 -- 调用函数 select的参数填充  获取新连接 注意点 -- 通信时的调用函数 添加新fd到

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器