给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
需要体系化学习资料的朋友,可以加我V获取:vip204888 (备注网络安全)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢!
个人博客链接: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,和前面的不同是这里是非对称加密。
学习路线:
这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:
需要体系化学习资料的朋友,可以加我V获取:vip204888 (备注网络安全)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!