JWT 专题
| 2023-3-27
0  |  Read Time 0 min

JWT 相关

JWT 的解密可以在此处完成,同时 JWT 由三部分组成:Header,Payload以及Secret,前两部分由base64编码,并且三个部分用 . 进行拼接

web345

知识点

  • JWT 的解码与使用
  • JWT 无密钥情况下可任意修改前方数据

做题

从 Cookie 中可获得 JWT 的数据,并放入 jwt.io
notion image
 
由 alg:None ,我们可以知道该jwt无签名算法,我们可以任意修改数据。
但是这里编码后的jwt不知道为什么少了个.,在下一题缺少这个.又无法正常提交
notion image
右键查看源代码,发现有一个访问 /admin 的提示,但注意这里不应该访问 /admin而应该访问 /admin/ ,否则将会错误地跳转到 80 端口的页面导致404。
但是此题无法依照wp做出来,先跳过。。。
notion image
将捕获后的auth发送至Decoder,解码后修改sub字段为admin再编码,编码后的内容去除等于号再发送至Repeater覆盖进行访问获得flag。

参考资料

JSON Web Token 入门教程
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法。 互联网服务离不开用户认证。一般流程是下面这样。 1、用户向服务器发送用户名和密码。 2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。 3、服务器向用户返回一个 session_id,写入用户的 Cookie。 4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。 5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。 这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。 举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现? 一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。 另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。 JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。 { "姓名": "张三", "角色": "管理员", "到期时间": "2018年7月1日0点0分" } 以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。 服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。 实际的 JWT 大概就像下面这样。 它是一个很长的字符串,中间用点(.
JSON Web Token 入门教程

web346

知识点

  • 修改加密方式为none使其可以任意修改数据内容

做题

将cookie中的jwt交由burpsuite解码,可以看见由三部分组成,分别为 Header.Content.Key
notion image
在此题中我们显然是没有办法直接拿到它的密钥的,但是在测试时,为了方便可以将加密方式设置为none,这样密钥设置为任何值都是可以,包括空值。
我们可以使用burpsuite来直接修改,将后面的key部分直接去除,然后再将中间段的sub将user改为admin即可
(测试了一下,发现上面这种方法并不可用)
我们还可以利用 Python 中的 pyjwt 库(使用 pip install pyjwt 来安装)来编码一段jwt串
从jwt中提取得到关键数据 Header {"alg":"HS256","typ":"JWT"},Content {"iss":"admin","iat":1630149052,"exp":1630156252,"nbf":1630149052,"sub":"admin","jti":"aeb0d5d3cb6eb7783cfb000aa990034f"} 并用pycharm进行编码。
编码后输出 eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzMDE0OTA1MiwiZXhwIjoxNjMwMTU2MjUyLCJuYmYiOjE2MzAxNDkwNTIsInN1YiI6ImFkbWluIiwianRpIjoiYWViMGQ1ZDNjYjZlYjc3ODNjZmIwMDBhYTk5MDAzNGYifQ.

参考资料

[CTFSHOW]JWT_Y4tacker的博客-CSDN博客_ctf jwt
有些师傅向我咨询WP,索性就发了吧,其实早就写好了,只是懒,在github仓库里囤着,有人说我写错了,这样吧群主改题也不是我能控制的,我能做的就是简简单单分享,也不想重做这些题仅参考 可以看看我的Github总结给自己看的, Y4tacker 首先打开题目,查看源码,接下来访问/admin被跳转回主页啥也没有发生 where is flag? 当然知道这个板块是JWT,自然而然我们看一眼Cookie,发现名为auth的一个cookie为 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoidXNlciJ9XQ 通过base64解密或者去jwt.io解码也行,得到结果 {"alg":"None","typ":"jwt"}[{"sub":"user"}] 所以我们尝试把sub对应的键值修改 {"alg":"None","typ":"jwt"}[{"sub":"admin"}] 把前面部分和后面部分分别base64-encode eyJhbGciOiJOb25lIiwidHlwIjoiand0In0 后面 W3sic3ViIjoiYWRtaW4ifV0= 把这两部分用点(.)拼接两部分并去掉等于号 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoiYWRtaW4ifV0 此时拿着这一串cookie去替换掉原来的值,之后访问/admin 即可获取flag JWT支持将算法设定为"None"。如果"alg"字段设为" None",那么签名会被置空,这样任何token都是有效的。 设定该功能的最初目的是为了方便调试。但是,若不在生产环境中关闭该功能,攻击者可以通过将alg字段设置为"None"来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。 首先拿到cookie eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNjg3MCwiZXhwIjoxNjA5MjQ0MDcwLCJuYmYiOjE2MDkyMzY4NzAsInN1YiI6InVzZXIiLCJqdGkiOiI5NDNkMGIzMjM3ODA2NjU5ZDJlMjA1ZTQyYjMxOTQ5NCJ9.9TUQLyYKs97ceFhZQ4BzkAuug6nCgLoMAbLH88kSOwo 解码 { "alg": "HS256", "typ": "JWT" } { "iss": "admin", "iat": 1609236870, "exp": 1609244070, "nbf": 1609236870, "sub": "user", "jti": "943d0b3237806659d2e205e42b319494" } 我们需要把sub字段改为admin 但是如果把签名算法改为none的化jwt.io那个网站就无法生成,这个时候可以使用python生成 将生成的字符串来替换原有的cookie获得flag 看见题干说是弱口令,去jwt.io解码 解码前 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzM2NiwiZXhwIjoxNjA5MjQ0NTY2LCJuYmYiOjE2MDkyMzczNjYsInN1YiI6InVzZXIiLCJqdGkiOiI3NzgzMjYzZDIxODVlYzhlYTBhYjY2MjZmMTk5MWRiOCJ9.aX8kzpC_p6HCUW60UdLVqjkDN97zmP0Ce6yETdaiv80 解码后发现还是HS256对称加密 { "alg": "HS256", "typ": "JWT" } { "iss": "admin", "iat": 1609237366, "exp": 1609244566, "nbf": 1609237366, "sub": "user", "jti": "7783263d2185ec8ea0ab6626f1991db8" } 既然题目说是弱口令我们尝试使用最简单的弱口令123456,成功,接下来我们只需要拿着这个密钥去生成jwt即可 密钥爆破工具: 看见题干说是爆破,猜都猜出来密钥了其实 ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzc0OSwiZXhwIjoxNjA5MjQ0OTQ5LCJuYmYiOjE2MDkyMzc3NDksInN1YiI6InVzZXIiLCJqdGkiOiI0ZDJlZWMwNDRiM2MxNTRjNmRjYmM5NzUzMmE3MmU3OCJ9.D0-CXOY9O1SvOvYqwYkUZ-ruOMbOMPh3dzOKiOamt2s Secret is "aaab" 得到密钥aaab,拿去生成即可 首先看代码,发现公私钥都放在了public文件夹下面,nodejs中可以直接访问此文件 /* GET home page.
[CTFSHOW]JWT_Y4tacker的博客-CSDN博客_ctf jwt

web347

知识点

  • 对称加密算法 HS256 密钥的爆破
  • Python strip 移除开头或结尾的字符,默认是空格或换行符

做题

根据参考资料1,可通过报错来判定key是否有效

通过 Python 脚本 + 常用密码破解

1.若签名直接校验失败,则 key_ 为有效密钥; 2.若因数据部分预定义字段错误 (jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError)导致校验失败,说明并非密钥错误导致,则 key_ 也为有效密钥; 3.若因密钥错误(jwt.exceptions.InvalidSignatureError)导致校验失败,则 key_ 为无效密钥; 4.若为其他原因(如,JWT 字符串格式错误)导致校验失败,根本无法验证当前 key_ 是否有效。 作者:littlebin404 链接:https://www.jianshu.com/p/acbb936e87df 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
考虑到一般人可能会使用自己的各种密码进行设置,可以用 web21 提供的字典进行测试。
我们可以通过下列代码进行破解
notion image

通过 jwt-cracker 进行破解

使用 BlackArch 或者 Kali 之类的,可以使用 jwt-cracker 进行全自动破解,但是速度较慢,命令为 jwt-cracker [jwt-token]
最后run出来密钥为 123456,可使用 web346 的代码重新合成一个 jwt

参考资料

基于JWT的token弱密钥爆破
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。直接根据token取出保存的用户信息,以及对token可用性校验,大大简化单点登录。 JWT=header+payload+signature(以.相隔) 例:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzYxMTk2NTYsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ.ud_qtIYt3QywJkmjPZIXVPaW3SnWCFj9dLVYa7iTEIg 下面详细介绍一下每个部分。 头部(Header) 用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。 {"alg":"HS256","typ":"JWT"} BASE64编码后为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 载荷(playload) (1)标准中注册的声明(建议但不强制使用) (2)公共的声明 (3)私有的声明(过期时间,用户名等信息) {"exp":1576119656,"username":"zdj","password":"123"} BASE64编码后:eyJleHAiOjE1NzYxMTk2NTYsInVzZXJuYW1lIjoiemRqIiwicGFzc3dvcmQiOiIxMjMifQ 签名(signature) header(base64)+payload(base64)使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分 ud_qtIYt3QywJkmjPZIXVPaW3SnWCFj9dLVYa7iTEIg 注:secret是保存在服务器端的签名私钥,就是我们今天的主角; 基于java实现JWT: 生成token: public static String Generatetoken(String username, String password) { String token = ""; try { // 过期时间 Date date = new Date(System.currentTimeMillis() + EXPIRE_DATE); // 秘钥及加密算法 Algorithm algorithm =
基于JWT的token弱密钥爆破

其他资料

web348

知识点

  • jwt-cracker 破解的使用

做题

notion image
使用 jwt-cracker 破解可得密码为 aaab
获得 token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzMDE2MDU2OSwiZXhwIjoxNjMwMTY3NzY5LCJuYmYiOjE2MzAxNjA1NjksInN1YiI6ImFkbWluIiwianRpIjoiN2E2MmVkNzQxNDFmYmE5OGY0MDVjYTNmZTIzZWJiOTEifQ.Ry2pggYXHznUje2KnM2In8Tku3RwuftuKIY3t4X3Hns
notion image

web349

知识点

  • node.js 中 Express 可通过 public 文件夹映射静态文件,从而下载

题目代码

做题

由题,我们可以得知其密钥存放于 /public/private.key,下载获得,并且编写 node.js 代码,注意需要提前安装好 jsonwebtoken 的 npm 包
得到 token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2MzAxNjIwOTd9.npKuv9ByHR6GG5v6vVtpMcjBnfKvWKk2QpklGZEcdTvla_qNFxC6N8mjRTBE5pTUDtGLCthrUWI860hL0GfE6Yyj3hMhOvwP53KqXeGbcG4rwl3kslQ-q92TeeVoLgQW83-M855bEE5_dS_YQsVhJfqdaBKoh-j9gE2fX_bnqDI
同时,题目要求验证的时候使用 POST,丢到 burpsuite 里面一把梭
notion image

web350

做题

这题是一个白盒分析题,可以通过参数 env=development 来使其报出错误。由于压缩包里没有 private.key ,因此想要暴力破解密钥是不太可能的。同时,cookie中的auth参数提交到 index.js 后经由 jwt.verify 验证,如果 decoded 为undefined则校验失败。但经过测试,发现连它生成的jwt我直接post都没法进行到下一步,所以我决定看wp
通过将算法调整为HMAC变体(HS256/HS384/HS512)并使用公共可用公钥对其进行签名,我们可以欺骗服务使用机密变量中的硬编码公钥验证HMAC令牌。
原来 JWT 在没有强制使用 RS256 的时候,还可以使用 public.key 与 HS256 来假装让它进行对称加密,真是tql。此处的public.key可以直接在网站上下载,直接输入 /public.key
这样下来,解题就很简单了,我们用公钥签名,然后直接把jwt交上去试试
按照代码,我们这里还需要使用 POST 方式来进行请求
notion image

参考资料

[CTFSHOW]JWT_Y4tacker的博客-CSDN博客_ctf jwt
有些师傅向我咨询WP,索性就发了吧,其实早就写好了,只是懒,在github仓库里囤着,有人说我写错了,这样吧群主改题也不是我能控制的,我能做的就是简简单单分享,也不想重做这些题仅参考 可以看看我的Github总结给自己看的, Y4tacker 首先打开题目,查看源码,接下来访问/admin被跳转回主页啥也没有发生 where is flag? 当然知道这个板块是JWT,自然而然我们看一眼Cookie,发现名为auth的一个cookie为 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoidXNlciJ9XQ 通过base64解密或者去jwt.io解码也行,得到结果 {"alg":"None","typ":"jwt"}[{"sub":"user"}] 所以我们尝试把sub对应的键值修改 {"alg":"None","typ":"jwt"}[{"sub":"admin"}] 把前面部分和后面部分分别base64-encode eyJhbGciOiJOb25lIiwidHlwIjoiand0In0 后面 W3sic3ViIjoiYWRtaW4ifV0= 把这两部分用点(.)拼接两部分并去掉等于号 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoiYWRtaW4ifV0 此时拿着这一串cookie去替换掉原来的值,之后访问/admin 即可获取flag JWT支持将算法设定为"None"。如果"alg"字段设为" None",那么签名会被置空,这样任何token都是有效的。 设定该功能的最初目的是为了方便调试。但是,若不在生产环境中关闭该功能,攻击者可以通过将alg字段设置为"None"来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。 首先拿到cookie eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNjg3MCwiZXhwIjoxNjA5MjQ0MDcwLCJuYmYiOjE2MDkyMzY4NzAsInN1YiI6InVzZXIiLCJqdGkiOiI5NDNkMGIzMjM3ODA2NjU5ZDJlMjA1ZTQyYjMxOTQ5NCJ9.9TUQLyYKs97ceFhZQ4BzkAuug6nCgLoMAbLH88kSOwo 解码 { "alg": "HS256", "typ": "JWT" } { "iss": "admin", "iat": 1609236870, "exp": 1609244070, "nbf": 1609236870, "sub": "user", "jti": "943d0b3237806659d2e205e42b319494" } 我们需要把sub字段改为admin 但是如果把签名算法改为none的化jwt.io那个网站就无法生成,这个时候可以使用python生成 将生成的字符串来替换原有的cookie获得flag 看见题干说是弱口令,去jwt.io解码 解码前 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzM2NiwiZXhwIjoxNjA5MjQ0NTY2LCJuYmYiOjE2MDkyMzczNjYsInN1YiI6InVzZXIiLCJqdGkiOiI3NzgzMjYzZDIxODVlYzhlYTBhYjY2MjZmMTk5MWRiOCJ9.aX8kzpC_p6HCUW60UdLVqjkDN97zmP0Ce6yETdaiv80 解码后发现还是HS256对称加密 { "alg": "HS256", "typ": "JWT" } { "iss": "admin", "iat": 1609237366, "exp": 1609244566, "nbf": 1609237366, "sub": "user", "jti": "7783263d2185ec8ea0ab6626f1991db8" } 既然题目说是弱口令我们尝试使用最简单的弱口令123456,成功,接下来我们只需要拿着这个密钥去生成jwt即可 密钥爆破工具: 看见题干说是爆破,猜都猜出来密钥了其实 ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzc0OSwiZXhwIjoxNjA5MjQ0OTQ5LCJuYmYiOjE2MDkyMzc3NDksInN1YiI6InVzZXIiLCJqdGkiOiI0ZDJlZWMwNDRiM2MxNTRjNmRjYmM5NzUzMmE3MmU3OCJ9.D0-CXOY9O1SvOvYqwYkUZ-ruOMbOMPh3dzOKiOamt2s Secret is "aaab" 得到密钥aaab,拿去生成即可 首先看代码,发现公私钥都放在了public文件夹下面,nodejs中可以直接访问此文件 /* GET home page.
[CTFSHOW]JWT_Y4tacker的博客-CSDN博客_ctf jwt
  • GitTalk
Catalog