沉铝汤的破站

IS LIFE ALWAYS THIS HARD, OR IS IT JUST WHEN YOU'RE A KID

JWT的利用

0x00 什么是JWT


JWT的全名是JSON Web Token,利用JSON储存信息,采用签名保证数据的完整性,服务端只储存密钥,用于验证token是否被修改,进而实现用户身份的验证。

0x01 JWT的格式


image-20210203153437653

JWT由三部分组成,分别是headerpayloadsignature,每一部分由圆点.分隔开。

上图中的红色部分,即为header部分

header中用JSON指明了token的类型和签名所采用的加密算法,然后经过base64URL处理,明文如下:

image-20210203154353758

如图,alg表示的即为算法,typ表示的是token的类型

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

PAYLOAD

上图中的紫色部分即为payload部分

payload中用JSON表示实际传送的数据,其中有七个官方字段:

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

除此以外,还可以自定义字段(如上图中的payload),然后再对其进行base64URL编码,明文如下:

image-20210203155556335

SIGNATURE

上图中的浅蓝色部分即为signature部分

签名采用了header中所指定的算法再加上密钥key进行签名处理,具体如下图所示:

image-20210203160054173

其中123即是上图JWT所采用的key

图中解析与构造JWT的来源是jwt.io,可用来解析和构造比赛中遇到的JWT

0x03 JWT 的伪造


密钥的爆破

由上文可知,JWT不储存在服务端,所以如果我们可以修改JWT并通过了服务端的验证,有时候就可以获得额外的权限。但是因为JWT有签名保证了数据的完整性,所以我们必须要知道密钥key,才能做到修改。

好在JWT的头部,只采用base64url,并且其中指定了签名所采用的算法,所以我们可以轻松知道签名算法。如果我么们这时候,可以爆破或者用其他方式获得密钥,那么我们便可以伪造一个JWT用于身份验证。

这里有一个用C语言写成的JWT密钥爆破工具: brendan-rius/c-jwt-cracker

Usage:$ > ./jwtcrack yourJWT

JWT的生成

如果获得了密钥,即可轻松构造出一个JWT。要构造JWT,既可以使用上文所用的jwt.io,也可以使用Python中的pyjwt库,一个脚本如下:

import jwt
token = jwt.encode(
    {
    "username": "admin",
    "password": "1",
    },
    algorithm = "HS256",
    key = "yourKey"
)
print(token) 

0x03 从加密算法下手


空加密

有的JWT库支持空加密,即首部中指明签名所采用的算法是None。这时候,签名就没啥用了,如果开发者在上线了的环境中忘记关闭,那么攻击者提交任何数据都可以通过验证。

要构造加密算法为None的JWT,并不可以借助jwt.io,因为这通常是恶意的,但是我们依然可以使用上文的Python脚本,提交到服务端的格式为header部分.payload部分.

将RS256更改为HS256

HS256是对称加密算法,加密和解密都采用同一密钥。而RS256是非对称加密算法,数据采用公钥加密,私钥解密。所以要通过一个使用了RS256加密的JWT验证,不仅要知道公钥,还需要知道私钥,但一般来说私钥是很难有机会获取的,但公钥却是比较容易获得的。

因此,我们可以利用试想一下,如果一个原本采用RS256的JWT,被我们改为了HS256并知晓了公钥,这时服务端就会使用同一个密钥进行解密,也就是使用我们所获得公钥进行验证,这样便通过了验证。

0x04 利用首部可选参数kid


什么是kid

kid是JWT首部的一个可选参数,全名为KEY ID,用来标识验证token该使用哪一个密钥。

image-20210203233310328

SQL注入

如果服务端使用kid进行了数据的查询,则可能会存在SQL的问题。

"kid": "foobar' union select 'hackerkey'"

由于序号为foobar的密钥并不存在,所以联合查询会返回后面的hackerkey,这样就将密钥变成了可控的了。

kid还可能造成RCE和目录遍历,不过我就先不写了😃;还有修改参数jku和x5u的,感兴趣的话自己查吧。

0x05参考文章


浅谈JWT绕过 - Von的博客 | Von Blog (v0n.top)

攻击JWT的一些方法 - 先知社区 (aliyun.com)

JWT攻击手册:如何入侵你的Token (qq.com)

JSON Web Token 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)

对jwt的安全测试方式总结 - SAUCERMAN (saucer-man.com)

JWT token破解绕过 - Junay的博客 (delcoding.github.io)

认识JWT - 废物大师兄 - 博客园 (cnblogs.com)