一个用C语言编写的多线程JWT暴力破解工具。如果你非常幸运或者拥有巨大的计算能力,这个程序应该能找到JWT令牌的密钥,从而允许你伪造有效的令牌。仅用于测试目的,不要给自己惹麻烦 :)
我使用了Apple的Base64实现,并做了一些小修改。
docker build . -t jwtcrack
docker run -it --rm jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.cAOIAifu3fykvhkHpbuhbvtH807-Z2rI1FS3vX1XMjE
请确保已安装OpenSSL的头文件。
在Ubuntu上,可以用以下命令安装:apt-get install libssl-dev
make
如果你使用Mac,可以通过brew install openssl安装OpenSSL,但头文件会存放在不同的位置:
make OPENSSL=/usr/local/opt/openssl/include OPENSSL_LIB=-L/usr/local/opt/openssl/lib
$ > ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.cAOIAifu3fykvhkHpbuhbvtH807-Z2rI1FS3vX1XMjE
以下哈希函数支持用于HMAC,即生成基于密钥的哈希消息认证码:"sha256"对应JSON的HS256(使用SHA-256的HMAC),"sha384"对应HS384,"sha512"对应HS512。你可以指定任何其他哈希函数的名字,就像它在OpenSSL中命名的那样。如果OpenSSL允许该哈希函数用于HMAC,那么jwtcrack将尝试解码密钥。然而,由于jwtcrack只是一个解码器,无法保证该算法确实被用于编码,更不用说在"JSON Web算法"RFC允许的算法列表中了。有关更多细节,请参阅RFC 7518第3.1节。
在以下示例中,我们使用sha256哈希函数(对应JSON的HS256,即HMAC-SHA256),将"sha256"作为最后一个命令行参数。此外,在本例中,我们指定最大密钥长度为5个字符,并将字母表限制为以下字符:ABCSNFabcsnf1234
$ > ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.cAOIAifu3fykvhkHpbuhbvtH807-Z2rI1FS3vX1XMjE ABCSNFabcsnf1234 5 sha256
在上面的例子中,密钥是Sn1f,在一台2019年左右生产的普通笔记本(例如搭载Ice Lake微架构的Intel CPU)上,耗时不到一秒。使用了GCC 9.3.0版本,编译参数为"-O3",并链接了OpenSSL 1.1.1f库(Linux Ubuntu 20.04.1 LTS)。
接下来这个例子中,我们使用"sha512"作为最后一个命令行参数来指定HS512(HMAC-SHA512),同时指定最大密钥长度为9个字符,并将字母表限制为以下七个拉丁小写字母:"adimnps"。
$ > ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiYWRtaW4ifQ.RnWtv7Rjggm8LdMU3yLnz4ejgGAkIxoZwsCMuJlHMwTh7CJODDZWR8sVuNvo2ws25cbH9HWcp2n5WxpIZ9_v0g adimnps 9 sha512
在上面的例子中,密钥是adminpass,在一台搭载Intel Core i7 1065G7 CPU(Ice Lake微架构,2019年)的笔记本上,平均解码时间约为15秒(基础频率1.30 GHz,最大睿频3.90 GHz)。由于多线程,用户模式下每个核心消耗的CPU秒数总和平均约为100秒来解码该密钥。
使用"sha384"的示例:
$ > ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJyb2xlIjoiYWRtaW4ifQ.31xCH3k8VRqB8l5qBy7RyqI2htyCskBy_4cIWpk3o43UkIMW-IcjTUEL_NyFXUWJ 0123456789 6 sha384
/usr/bin/time -f "每个CPU核心直接消耗的CPU秒总数:%U\n进程使用的实际挂钟时间:%E" ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiYWRtaW4ifQ.RnWtv7Rjggm8LdMU3yLnz4ejgGAkIxoZwsCMuJlHMwTh7CJODDZWR8sVuNvo2ws25cbH9HWcp2n5WxpIZ9_v0g adimnps 9 sha512
我使用的Base64实现(来自Apple)有时存在bug,因为并非所有Base64实现都是相同的。因此,有时解码你的Base64令牌只会部分成功,这样你可能会找到一个并非正确的密钥。
如果有人愿意实现一个更健壮的Base64实现,那就太好了 :)