开通VIP,畅享免费电子书等14项超值服
首页
好书
留言交流
下载APP
联系客服
2023.10.29广东
星标不再迷路,谢谢大家!
JWT(JSONWebToken)的结构由三部分组成,分别是Header、Payload和Signature,下面是每一部分的详细介绍和示例:
Header包含了JWT使用的算法和类型等元数据信息,通常使用JSON对象表示并使用Base64编码,Header中包含两个字段:alg和typalg(algorithm):指定了使用的加密算法,常见的有HMAC、RSA和ECDSA等算法typ(type):指定了JWT的类型,通常为JWT
下面是一个示例Header:
其中alg指定了使用HMAC-SHA256算法进行签名,typ指定了JWT的类型为JWT
下面是一个示例Payload:
Signature是使用指定算法对Header和Payload进行签名生成的,用于验证JWT的完整性和真实性,Signature的生成方式通常是将Header和Payload连接起来然后使用指定算法对其进行签名,最终将签名结果与Header和Payload一起组成JWT,Signature的生成和验证需要使用相同的密钥,下面是一个示例Signature
其中HMACSHA256是使用HMACSHA256算法进行签名,header和payload是经过Base64编码的Header和Payload,secret是用于签名和验证的密钥,最终将Header、Payload和Signature连接起来用句点(.)分隔就形成了一个完整的JWT,下面是一个示例JWT,其中第一部分是Header,第二部分是Payload,第三部分是Signature,注意JWT中的每一部分都是经过Base64编码的,但并不是加密的,因此JWT中的信息是可以被解密的
JWT的工作流程如下:
Step1:用户携带JWS(带有签名的JWT)访问应用
Step2:应用程序解码JWS得到JKU字段
Step3:应用根据JKU访问返回JWK的服务器
Step4:应用程序得到JWK
Step5:使用JWK验证用户JWS
Step6:验证通过则正常响应
JWT(JSONWebToken)的签名验证过程主要包括以下几个步骤:
下面是一个使用JAVA进行JWT签名验证的示例代码:
在上面的示例代码中使用jwt库进行JWT的签名和验证,首先构建了一个JWT,然后将其分离为Header、Payload和Signature三部分,使用parseClaimsJws函数对JWT进行解析和验证,从而获取其中的Payload中的信息并进行验证,最后如果解析和验证成功,则说明JWT是有效的,否则说明JWT是无效的,在实际应用中应该将SECRET_KEY替换为应用程序的密钥
Step3:此时在我们的burpsuite中我们可以看到如下的会话信息
此时查询当前用户可以看到会显示当前用户为wiener:
截取上面中间一部分base64编码的部分更改上面的sub为'administrator'
构造一个sub为'administrator'的载荷并将其进行base64编码处理:
替换之后重新发送请求:
按照题目要求访问/admin路径,发现两个删除用户的调用接口:
请求敏感链接——删除用户carlos
完成靶场的解答:
在JWT的Header中alg的值用于告诉服务器使用哪种算法对令牌进行签名,从而告诉服务器在验证签名时需要使用哪种算法,目前可以选择HS256,即HMAC和SHA256,JWT同时也支持将算法设定为'None',如果'alg'字段设为'None',则标识不签名,这样一来任何token都是有效的,设定该功能的最初目的是为了方便调试,但是若不在生产环境中关闭该功能,攻击者可以通过将alg字段设置为'None'来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站
Step4:捕获到的数据报信息如下所示
截取JWT的第二部分对其进行base64解码:
将上述的sub字段值更改为'administrator'
Step4:在使用wiener用户的凭据访问/admin是会提示401Unauthorized
Step5:将第一步分的alg参数改为none
更改之后的header部分:
替换JWTToken中的第二部分为之前我们构造的信息,同时移除签名部分,再次请求数据获取到敏感数据链接
调用敏感链接移除用户信息,完成解题操作:
在JT中密钥用于生成和验证签名,因此密钥的安全性对JWT的安全性至关重要,一般来说JWT有以下两种类型的密钥:
下面是一个使用JWT和对称密钥的JAVA示例代码:
在这里我们也建议使用hashcat来强力破解密钥,您可以手动安装hashcat,也可以在KaliLinux上使用预先安装好的hashcat,您只需要一个来自目标服务器的有效的、签名的JWT和一个众所周知的秘密的单词表然后就可以运行以下命令,将JWT和单词列表作为参数传入:
hashcat-a0-m16500
实验步骤:Step1:点击上述'Accessthelab'进入到靶场环境
Step3:捕获到如下有效的JWT凭据信息
Step5:使用字典进行暴力猜解操作
Step1:克隆项目到本地
Step2:安装依赖库
pip3installpycryptodomexStep3:运行jwt_tool并查看用法信息
附加扩展:
payload(前):
payload(新):
Signer:
最终高权限的JWTtoken如下:
Step6:访问/admin路径
Step7:调用接口删除用户完成解答
如果服务器端使用一个非常脆弱的密钥,我们甚至有可能一个字符一个字符地来暴力破解这个密钥,根据JWS规范只有alg报头参数是强制的,然而在实践中JWT报头通常包含几个其他参数,以下是攻击者特别感兴趣的:
这些用户可控制的参数每个都告诉接收方服务器在验证签名时应该使用哪个密钥,下面我们将介绍如何利用这些参数来注入使用您自己的任意密钥而不是服务器的密钥签名修改过的JWT
下面我们介绍如何通过JWK参数注入自签名的JWT,JWS(JSONWebSignature)规范描述了一个可选的jwkheader参数,服务器可以使用该参数以jwk格式将其公钥直接嵌入令牌本身,您可以在下面的JWThead中看到具体的示例:
Step1:点击'ACCESSTHELAB'访问靶场
Step5:下面我们开始操作,不过在此之前我们得先武器化以下自己,在Burpsuite界面选择'Extender'选项卡,紧接着点击'BAppStore'安装'JWTEditor'
之后你可以看到如下的选项卡界面
Step6:生成一个新的RSA密钥
Step7:刷新页面拦截到请求并将请求发送到Repeat模块
Step8:在Repeat模块,我们切换到JSONWebToken选项卡,修改JWT的有效负载将sub内容修改为administrator
Step9:点击'Attack',然后选择'EmbeddedJWK',出现提示时选择您新生成的RSA密钥
Step10:之后成功越权
Step11:调用敏感操作接口删除carlos用户完成解题
Step1:首先点击上方的'ACCESSTHELAB'选项卡进入实验环境
Step4:使用burpsuite生成一个新的RSA密钥
Step5:发送请求到repeat
Step6:复制公钥作为JWK
Step7:在题目中选择'Goeoexploitserver',然后加上key头并保存到exploit的body中
Step8:然后切换至repeat的'JSONWebToken'界面,将kid修改成自己生成的JWK中的kid值,将jku的值改为exploit
Step9:切换sub为administrator
Step10:点击下面的sign,选择Don’tmodifyheader模式
Step11:更改请求路径发送请求成功越权
Step12:请求敏感路径删除carlos用户
Step13:成功解题
服务器可能使用几个密钥来签署不同种类的数据,因此JWT的报头可能包含kid(密钥id)参数,这有助于服务器在验证签名时确定使用哪个密钥,验证密钥通常存储为一个JWK集,在这种情况下服务器可以简单地查找与令牌具有相同kid的JWK,然而JWS规范没有为这个ID定义具体的结构——它只是开发人员选择的任意字符串,例如:它们可能使用kid参数指向数据库中的特定条目,甚至是文件的名称,如果这个参数也容易受到目录遍历的攻击,攻击者可能会迫使服务器使用其文件系统中的任意文件作为验证密钥,例如:
Step1:点击上方'AccessTheLab'进入靶场
Step4:使用burpsuite的插件生成一个对称密钥(SymmetricKey)并将k的值修改为'AA=='即为null
Step5:拦截一个请求将其发送到repeat模块
Step6:此时直接访问/admin——提示'401Unauthorized'
Step7:在JSONWebToken界面中修改kid值和sub进行目录遍历,这里的'/dev/null'文件名与'AA=='一致都为null,对称密钥,所以可以成功绕过
Step8:点击sign选择OCT8的密钥攻击
Step9:成功越权
Step10:调用敏感接口删除carlos用户完成解题
算法混淆攻击(也称为密钥混淆攻击)是指攻击者能够迫使服务器使用不同于网站开发人员预期的算法来验证JSONweb令牌(JWT)的签名,这种情况如果处理不当,攻击者可能会伪造包含任意值的有效jwt而无需知道服务器的秘密签名密钥JWT可以使用一系列不同的算法进行签名,其中一些,例如:HS256(HMAC+SHA-256)使用'对称'密钥,这意味着服务器使用单个密钥对令牌进行签名和验证,显然这需要像密码一样保密
使用这种方法的网站开发人员认为它将专门处理使用RS256这样的非对称算法签名的JWT时,问题就出现了,由于这个有缺陷的假设他们可能总是传递一个固定的公钥给方法,如下所示:
publicKey=
Step1:点击'Accessthelab'访问靶场
Step4:服务器有时通过映射到/jwks.json或/.well-known/jwks.json的端点将它们的公钥公开为JSONWebKey(JWK)对象,比如大家熟知的/jwks.json,这些可能被存储在一个称为密钥的jwk数组中,这就是众所周知的JWK集合,即使密钥没有公开,您也可以从一对现有的jwt中提取它
Step5:在Burpsuite的JWTEditorKeys中点击'NewRSAKey',用之前泄露的JWK而生成一个新的RSAKey
Step6:选中'CopyPublicKeyasPEM',同时将其进行base64编码操作,保存一下得到的字符串(备注:上下的一串-----ENDPUBLICKEY-----不要删掉)
base64后结果:
Step7:在JWTEditorKeys处,生成新的对称加密Key,用之前保存的base64编码去替换k的值
Step8:捕获请求数据报并将其发送到repeat模块
此时直接请求/admin是无法请求到的
Step9:随后修改alg为HS256,修改sub为administrator并进行Sign操作
Step10:重新发送数据包可以看到回显成功
Step11:请求敏感连接删除用户完成解题
随后将其放到Port提供的docker工具里面运行,运行的命令如下
jwt_forgery.py脚本会输出一系列token的存在情况值
Step2:这里我们尝试每一个TemperedJWT,Port这里给了提示说是X.509形式的,所以我们只需要将X.509形式的JWT进行验证即可,当Response回应200时代表token是有效的,若为302则代表了重定向,下图是一个成功的案例
Step3:将JWT的Base64编码拿过来先放到记事本里面暂存,在Burpsuite的JWTEditorKeys点击NewSymmetricKey,将上面的Base64编码拿过来替换此对称密钥的k值,生成对称密钥之后进行和之前攻击一致的Sign操作
靶场JWT信息如上所示,而在实战中我们可以去抓包,如果抓到的数据包中有类似这样的JWT认证那我们就可以直接拿去解密了,我们拿到的数据是这样的:
在这里我们可以看到payload部分的数据解密出来后包含password字段信息,后面解出来的是一串MD5数据,之后我们将其拿到MD5在线解密网站进行解密操作:
JWT中的密钥是用于对令牌进行签名或加密的关键信息,在实现JWT时密钥通常存储在应用程序代码中即所谓的'硬编码',这种做法可能会导致以下安全问题:
JWT密钥硬编码:
JWTToken有效期为1小时
但是在过期后发现使用之前过期的JWTToken可以继续进行会话操作
测试效果如下:
用于利用CRLF漏洞的脚本
★
欢迎加入星球!
代码审计+免杀+渗透学习资源+各种资料文档+各种工具+付费会员