freeBuf
主站

分类

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

特色

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

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

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

FreeBuf+小程序

FreeBuf+小程序

JWT攻击常用的两种算法
2021-10-03 08:57:46

什么是JWT

JWT全称JSON Web Token,是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。JWT通过将用户信息封装成token的方式进行身份验证。

JWT的组成

一个JWT实际上就是一个字符串,它由三部分组成,头部载荷签名

JWT 这种结构化体可以分为HEADER(头部)、PAYLOAD(数据体)和 SIGNATURE(签名)三部分。经过签名之后的 JWT 的整体结构,是被句点符号分割的三段内容,结构为 header.payload.signature。详情请见https://jwt.io/introduction

例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

https://jwt.io/网站中解密得到

1633222473_6158ff49442b5c36f5636.png!small?1633222473390

HEADER:该部分其实也是一个 JSON 对象,表示装载令牌类型和算法等信息,是 JWT 的头部。其中,typ 表示第二部分 PAYLOAD 是 JWT 类型,alg 表示使用 HS256 对称签名的算法。

PAYLOAD:数据体主要是我们的结构化数据,这组数据基本上都是我们自定义的信息。但是有几个关键点大家需要注意一下:exp(令牌的过期时间戳)、iat(令牌颁发的时间戳)

而基本的payload的部分由如下部分组成:

iss: 该JWT的签发者

sub: 该JWT所面向的用户

aud: 接收该JWT的一方

exp(expires): 什么时候过期,这里是一个Unix时间戳

iat(issued at): 在什么时候签发的

SIGNATURE:表示对 JWT 信息的签名。其实就是对HEADER与PAYLOAD进行一次加密处理,主要是验证整个JWT内容有没有被篡改。首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

这几个部分当然不是直接写在token中,那样太明显了,而是由base64加密成字符串,JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

JWT攻击实施

从之前的JWT分析过程中我们发现我们可以伪造任意用户获得无限的访问权限,而且还可能进一步发现更多的安全漏洞,如信息泄露,越权访问,SQLi,XSS,SSRF,RCE,LFI等。

但是我们要利用这个漏洞首先就要知道这个是否是利用了JWT进行身份验证

验证是否使用JWT

首先我们需要识别应用程序正在使用JWT,最简单的方法是在代理工具的历史记录中搜索JWT正则表达式:

[= ]ey[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*-稳定的JWT版本
[= ]ey[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]*-所有JWT版本(可能误报)

确保同时“区分大小写”和匹配“正则表达式”

这里是使用常用的burpsuit来进行演示的

1633222487_6158ff57cddde3ad3f5e8.png!small?1633222487978

JWT漏洞利用

当我们获得一个基于JWT的token时,我们可以利用什么呢?(攻击方式)

被泄露的敏感信息

由于Header和Payload部分是使用可逆base64方法编码的,因此任何能够看到令牌的人都可以读取数据。可以通过base64decode分别将每个部分解码就可以去阅读token内的数据。

防御措施:由于其中明文传递的username和password都是可以看到的(因此,Token不能随意公布,发送的数据不得包含任何敏感数据(例如密码))

将算法修改为none

算法是指将Header部分的alg(全称algorithm),也就是alg字段被设置为空,那么SIGNATURE的签名部分将被置空,这样的话任何token都将是有效的

设定该功能的最初目的是为了方便调试。但是,若不在生产环境中关闭该功能,攻击者可以通过将alg字段设置为“None”来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。

例如:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4iLCJhY3Rpb24iOiJ1cGxvYWQifQ.

这就是将alg设置为none的结果,解构后的JWT为:

{"typ":"JWT","alg":"none"}.

{"user":"admin","action":"upload"}.

[No signature!]

那么如果返回页面为有效页面那么攻击成功,存在此种漏洞,反之不存在

防御措施:JWT配置应该指定所需的签名算法,不要指定”none”。(也就是必须是用此种算法得来的token才会被接受s)

密钥混淆攻击

JWT最常用的两种算法是HMACRSA

HMAC(对称加密算法)用同一个密钥对token进行签名和认证。

而RSA(非对称加密算法)需要两个密钥,先用私钥加密生成JWT,然后使用其对应的公钥来解密验证。

如果将alg参数改成HS256,这样就将算法RS256修改为HS256,让服务器不使用对称加密,转而使用非对称加密算法

那么,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。

后端代码会使用RSA公钥+HS256算法进行签名验证。进而攻击者将达到目的。

防御措施:JWT配置应该只允许使用HMAC算法或公钥算法,决不能同时使用这两种算法。

无效签名攻击

无效签名是指当用户端提交请求给应用程序,服务端可能没有对token签名进行校验,这样,攻击者便可以通过提供无效签名简单地绕过安全机制。

实际上,就和上面将算法置空很像,同样是签名无效了,导致攻击者只需要更换user参数就可以实现越权访问,可能是横向越权也可能是纵向越权

防御措施:严格审核JWT签名

暴力破解密钥或密钥泄露

HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,这意味着对令牌进行签名的密钥也用于对其进行验证。由于签名验证是一个自包含的过程,因此可以测试令牌本身的有效密钥,而不必将其发送回应用程序进行验证。

我们可以利用github上的工具c-jwt-cracker来完成,但是局限性很大。

首先秘钥不能太复杂,其次还需要一段已知的签过名的token。

如果可以破解HMAC密钥,则可以伪造令牌中的任何内容,攻击者就可以随意的进行越权。

如果我们无法通过暴力破解,那么可以通过其他手段得到密钥也可以实现伪造令牌的任何内容,实现各种操作

修改KID

kid(key ID)是JWT的header部分的可选参数,作用是用来指定加密算法秘钥。

开发人员可以用它标识认证token的某一密钥

例如:

{
"alg": "HS256",
"typ": "JWT",
"kid": "1"         //使用密钥1验证token
//“kid”:”/home/jwt/1.pem”  //这个kid参数还可以是文件路径
}

由于kid参数是用户可控的,那么攻击者就可以用来构造攻击,比如服务器更新了密钥,但是旧的密钥并未删除且该密钥已经被攻击者所知,或者通过ftp等渠道上传了密钥,那么就会导致攻击者能够直接控制签名验证从而绕过签名

KID的其他攻击利用方式:

  1. sql注入

KID也可以用于在数据库中检索密钥。在该情况下,攻击者很可能会利用SQL注入来绕过JWT安全机制。

通过对KID的修改,导致数据库信息泄露

例如:

“kid”:”1 ' UNION SELECT 'key';--”    //使用字符串"key"验证token

这个注入会导致应用程序返回字符串“ key”,因此我们得到了key字符串的值,服务器也将以key的值来验证token

举例:

【网鼎杯2020玄武组】js_on

通过提示,我们知道存在token注入,token分为三段,第一段为header,第二段为payload,第三段为签名,header可以不变,payload存在自定义字段
将payload的进行base64解码

{"user":"admin","news":"key: xRt*YMDqyCCxYxi9a@LgcGpnmM2X8i&6"}

这里的user字段实际就是注入点

写入payload:

{"user":"admin'/**/and/**/'1'='2'#","news":"key: xRt*YMDqyCCxYxi9a@LgcGpnmM2X8i&6"}

将其进行base64加密,之后通过jwt官方网站得到token
jwt官网:https://jwt.io/#debugger

1633222511_6158ff6fe7710a3c31cae.png!small?1633222512074


  1. RCE(任意命令执行)

有时候服务器会直接通过函数对KID文件进行调用,这时候我们可以通过这类函数执行系统命令,例如Ruby open()。攻击者只需在输入的KID文件名后面添加命令,即可执行系统命令

“kid”: "key_file" | whoami;

理论上,每当应用程序将未审查的头部文件参数传递给类似system(),exec()的函数时,都会产生此种漏洞。

操纵头部参数

除KID外,JWT标准还能让开发人员通过URL指定密钥。

下面是可以用来进行密钥指定的头部参数:

JKU

JKU全称JWKSet URL,它是头部的一个可选字段,用于指定链接到一组加密token密钥的URL。若允许使用该字段且不设置限定条件,攻击者就能托管自己的密钥文件,并指定应用程序,用它来认证token。

JWK

JWK全称JSON Web Key,使得攻击者能将认证的密钥直接嵌入token中

X5U,X5C

和JKU,JWK类似,攻击者可以通过对这种头部参数的控制决定验证Token的公钥证书或证书链。但是不同的是x5u以URI形式指定信息,而x5c允许将证书值嵌入token中。

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