首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JWT在CTF中的问题

JWT在CTF中的问题

作者头像
字节脉搏实验室
发布2020-04-25 13:54:51
5.6K0
发布2020-04-25 13:54:51
举报

0x00、知识点:

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案

它的构成:第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

类似于:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

header

jwt的头部承载两部分信息:

  • 声明类型,这里是jwt
  • 声明加密的算法 通常直接使用 HMAC SHA256

完整的头部就像下面这样的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

然后将头部进行Base64加密构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

payload

载荷就是存放有效信息的地方。这些有效信息包含三个部分。

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明 (建议但不强制使用) :

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可进行解码.

私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息。

定义一个payload:

{
  "sub": "1234567890",
  "name": "purplet",
  "admin": true,
  "secretid": 1
}

然后将其进行base64加密,得到Jwt的第二部分。

ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJwdXJwbGV0IiwNCiAgImFkbWluIjogdHJ1ZSwNCiAgInNlY3JldGlkIjogMQ0KfQ

signature

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。加密方式如下。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret');

最后将这三部分用.连接成一个完整的字符串,构成了最终的jwt。

0x01 、Node的JWT库的空加密缺陷

以下内容学习基于两道CTF题。

虎符CTF的WEB(easy_login)

该题开始是一个登录框,经过随意注册一个用户后,再进行登录后提示没有权限登录,这一点我们直接就可以猜测出是要求admin用户登录,然后我们在注册处利用BP抓包放包后可以看到有一串JWT的字符、

并且在登录时也会发现该JWT字符会作为身份验证部分与用户名、密码一起通过POST方法表单传递到后端进行验证。所以可以想到JWT的伪造,同时结合题目的描述与node有关,学习到node

的JWT库的空加密缺陷问题。对普通用户的JWT进行base64解码如下

解题:

首先注册登陆采用jwt认证,但是jwt的实现很奇怪,逻辑大概是,注册的时候会给每个用户生成一个单独的secret_token作为jwt的密钥,通过后端的一个全局列表来存储,登录的时候通过用户传过来的secretid取出对应的secret_token来解密jwt,如果解密成功就算登陆成功。

然而,node 的jsonwebtoken库存在一个缺陷,也是jwt的常见攻击手法,当用户传入jwt secret为空时 jsonwebtoken会采用algorithm none进行解密。

因为服务端 通过

 var secret = global.secretlist[secretid];
 jwt.verify(req.cookies.token,secret);

解密,我可以通过传入不存在的id,让secret为undefined,导致algorithm为none,然后就可以通过伪造jwt来成为admin

#pip3 install pyjwt
import jwt

token = jwt.encode({"secretid":"","username":"admin","password":"123456","iat":1587367857},algorithm="none",key="").decode(encoding='utf-8')

print(token)

因为我们知晓了JWT的原理,所以也可以直接对内容进行base64编码, 可以根据其node的JWT缺陷将secretid置为空,所以构造以下payload

{"alg":"HS256","typ":"JWT"}.{"secretid":"","username":"admin","password":"123456","iat":1587367857}.

对其直接进行base64加密后,注意“点”不要加密同时最后不要拼接第三段,用户名和密码写上构造的admin/123456,抓登陆包。

即可登录,获得flag

0x02、JWT-cookie伪造

[CISCN2019 华北赛区 Day1 Web2]ikun

该题我只对JWT部分进行记录

注册普通用户登录后首先可以看到有1000元

而按照题目要求需要购买lv6,它的价格又十分昂贵,抓包后看到有discount参数,尝试将其改的特别小,使我们能够购买成功。成功购买后但是出现

这就很明显需要我们越权进行登录,查看cookie此时可以看到一段JWT

看到JWT长度较短,所以可以考虑利用工具将JWT的第三段密钥爆破出来

工具链接如下:

https://github.com/brendan-rius/c-jwt-cracker

爆破密钥

知道密钥后,我们就可以任意构造JWT了,利用在线网站:https://jwt.io/

这样就实现了admin用户身份的伪造,将所得内容替换回去(可以利用火狐插件EditThisCookie),最终即可以admin用户身份登录。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节脉搏实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • header
  • payload
  • signature
  • 0x01 、Node的JWT库的空加密缺陷
  • 0x02、JWT-cookie伪造
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档